xref: /aosp_15_r20/frameworks/base/core/jni/android_content_res_ApkAssets.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define ATRACE_TAG ATRACE_TAG_RESOURCES
18 
19 #include "android_content_res_ApkAssets.h"
20 
21 #include <mutex>
22 
23 #include "android-base/logging.h"
24 #include "android-base/macros.h"
25 #include "android-base/stringprintf.h"
26 #include "android-base/unique_fd.h"
27 #include "androidfw/ApkAssets.h"
28 #include "core_jni_helpers.h"
29 #include "jni.h"
30 #include "nativehelper/ScopedUtfChars.h"
31 #include "signal.h"
32 #include "utils/Trace.h"
33 #include "utils/misc.h"
34 
35 using ::android::base::unique_fd;
36 
37 namespace android {
38 
39 static constexpr bool kLogWeakReachableDeletedAssets = false;
40 
41 static struct overlayableinfo_offsets_t {
42   jclass classObject;
43   jmethodID constructor;
44 } gOverlayableInfoOffsets;
45 
46 static struct assetfiledescriptor_offsets_t {
47   jfieldID mFd;
48   jfieldID mStartOffset;
49   jfieldID mLength;
50 } gAssetFileDescriptorOffsets;
51 
52 static struct assetsprovider_offsets_t {
53   jclass classObject;
54   jmethodID loadAssetFd;
55   jmethodID toString;
56 } gAssetsProviderOffsets;
57 
58 static struct {
59   jmethodID detachFd;
60 } gParcelFileDescriptorOffsets;
61 
62 // Keep in sync with f/b/android/content/res/ApkAssets.java
63 using format_type_t = jint;
64 enum : format_type_t {
65   // The path used to load the apk assets represents an APK file.
66   FORMAT_APK = 0,
67 
68   // The path used to load the apk assets represents an idmap file.
69   FORMAT_IDMAP = 1,
70 
71   // The path used to load the apk assets represents an resources.arsc file.
72   FORMAT_ARSC = 2,
73 
74   // The path used to load the apk assets represents the a directory.
75   FORMAT_DIRECTORY = 3,
76 };
77 
ApkAssetsFromLong(jlong ptr)78 Guarded<AssetManager2::ApkAssetsPtr>& ApkAssetsFromLong(jlong ptr) {
79   return *reinterpret_cast<Guarded<AssetManager2::ApkAssetsPtr>*>(ptr);
80 }
81 
CreateGuardedApkAssets(AssetManager2::ApkAssetsPtr assets)82 static jlong CreateGuardedApkAssets(AssetManager2::ApkAssetsPtr assets) {
83   auto guarded_assets = new Guarded<AssetManager2::ApkAssetsPtr>(std::move(assets));
84   return reinterpret_cast<jlong>(guarded_assets);
85 }
86 
DeleteGuardedApkAssets(Guarded<AssetManager2::ApkAssetsPtr> & apk_assets)87 static void DeleteGuardedApkAssets(Guarded<AssetManager2::ApkAssetsPtr>& apk_assets) {
88   apk_assets.safeDelete([&apk_assets](AssetManager2::ApkAssetsPtr* assets) {
89     if (!assets) {
90       ALOGW("ApkAssets: Double delete of native assets object %p, ignored", &apk_assets);
91     } else if (!*assets) {
92       ALOGW("ApkAssets: Empty native assets pointer in native assets object %p", &apk_assets);
93     } else {
94       // |RefBase| increments |StrongCount| for each |sp<>| instance, and |WeakCount| for
95       // both |sp<>| and |wp<>| instances. This means the actual |wp<>| instance count
96       // is |WeakCount - StrongCount|.
97       const auto useCount = (*assets)->getStrongCount();
98       const auto weakCount = (*assets)->getWeakRefs()->getWeakCount() - useCount;
99       if (useCount > 1) {
100         ALOGW("ApkAssets: Deleting an object '%s' with %d > 1 strong and %d weak references",
101               (*assets)->GetDebugName().c_str(), int(useCount), int(weakCount));
102       } else if constexpr (kLogWeakReachableDeletedAssets) if (weakCount > 0) {
103         ALOGW("ApkAssets: Deleting an ApkAssets object '%s' with %d weak references",
104               (*assets)->GetDebugName().c_str(), int(weakCount));
105       }
106     }
107   });
108   delete &apk_assets;
109 }
110 
111 class LoaderAssetsProvider : public AssetsProvider {
112  public:
Create(JNIEnv * env,jobject assets_provider)113   static std::unique_ptr<AssetsProvider> Create(JNIEnv* env, jobject assets_provider) {
114     return (!assets_provider) ? EmptyAssetsProvider::Create()
115                               : std::unique_ptr<AssetsProvider>(new LoaderAssetsProvider(
116                                     env, assets_provider));
117   }
118 
ForEachFile(const std::string &,android::base::function_ref<void (StringPiece,FileType)>) const119   bool ForEachFile(const std::string& /* root_path */,
120                    android::base::function_ref<void(StringPiece, FileType)> /* f */) const {
121     return true;
122   }
123 
GetPath() const124   std::optional<std::string_view> GetPath() const override {
125     return {};
126   }
127 
GetDebugName() const128   const std::string& GetDebugName() const override {
129     return debug_name_;
130   }
131 
IsUpToDate() const132   bool IsUpToDate() const override {
133     return true;
134   }
135 
~LoaderAssetsProvider()136   ~LoaderAssetsProvider() override {
137     const auto env = AndroidRuntime::getJNIEnv();
138     CHECK(env != nullptr)  << "Current thread not attached to a Java VM."
139                            << " Failed to close LoaderAssetsProvider.";
140     env->DeleteGlobalRef(assets_provider_);
141   }
142 
143  protected:
OpenInternal(const std::string & path,Asset::AccessMode mode,bool * file_exists) const144   std::unique_ptr<Asset> OpenInternal(const std::string& path,
145                                       Asset::AccessMode mode,
146                                       bool* file_exists) const override {
147     const auto env = AndroidRuntime::getJNIEnv();
148     CHECK(env != nullptr) << "Current thread not attached to a Java VM."
149                           << " ResourcesProvider assets cannot be retrieved on current thread.";
150 
151     jstring java_string = env->NewStringUTF(path.c_str());
152     if (env->ExceptionCheck()) {
153       env->ExceptionDescribe();
154       env->ExceptionClear();
155       return nullptr;
156     }
157 
158     // Check if the AssetsProvider provides a value for the path.
159     jobject asset_fd = env->CallObjectMethod(assets_provider_,
160                                              gAssetsProviderOffsets.loadAssetFd,
161                                              java_string, static_cast<jint>(mode));
162     env->DeleteLocalRef(java_string);
163     if (env->ExceptionCheck()) {
164       env->ExceptionDescribe();
165       env->ExceptionClear();
166       return nullptr;
167     }
168 
169     if (!asset_fd) {
170       if (file_exists) {
171         *file_exists = false;
172       }
173       return nullptr;
174     }
175 
176     const jlong mOffset = env->GetLongField(asset_fd, gAssetFileDescriptorOffsets.mStartOffset);
177     const jlong mLength = env->GetLongField(asset_fd, gAssetFileDescriptorOffsets.mLength);
178     jobject mFd = env->GetObjectField(asset_fd, gAssetFileDescriptorOffsets.mFd);
179     env->DeleteLocalRef(asset_fd);
180 
181     if (!mFd) {
182       jniThrowException(env, "java/lang/NullPointerException", nullptr);
183       env->ExceptionDescribe();
184       env->ExceptionClear();
185       return nullptr;
186     }
187 
188     // Gain ownership of the file descriptor.
189     const jint fd = env->CallIntMethod(mFd, gParcelFileDescriptorOffsets.detachFd);
190     env->DeleteLocalRef(mFd);
191     if (env->ExceptionCheck()) {
192       env->ExceptionDescribe();
193       env->ExceptionClear();
194       return nullptr;
195     }
196 
197     if (file_exists) {
198       *file_exists = true;
199     }
200 
201     return AssetsProvider::CreateAssetFromFd(base::unique_fd(fd),
202                                              nullptr /* path */,
203                                              static_cast<off64_t>(mOffset),
204                                              static_cast<off64_t>(mLength));
205   }
206 
207  private:
208   DISALLOW_COPY_AND_ASSIGN(LoaderAssetsProvider);
209 
LoaderAssetsProvider(JNIEnv * env,jobject assets_provider)210   explicit LoaderAssetsProvider(JNIEnv* env, jobject assets_provider) {
211     assets_provider_ = env->NewGlobalRef(assets_provider);
212     auto string_result = static_cast<jstring>(env->CallObjectMethod(
213         assets_provider_, gAssetsProviderOffsets.toString));
214     ScopedUtfChars str(env, string_result);
215     debug_name_ = std::string(str.c_str(), str.size());
216   }
217 
218   // The global reference to the AssetsProvider
219   jobject assets_provider_;
220   std::string debug_name_;
221 };
222 
NativeLoad(JNIEnv * env,jclass,const format_type_t format,jstring java_path,const jint property_flags,jobject assets_provider)223 static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, const format_type_t format,
224                         jstring java_path, const jint property_flags, jobject assets_provider) {
225   ScopedUtfChars path(env, java_path);
226   if (path.c_str() == nullptr) {
227     return 0;
228   }
229 
230   ATRACE_NAME(base::StringPrintf("LoadApkAssets(%s)", path.c_str()).c_str());
231 
232   auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
233   AssetManager2::ApkAssetsPtr apk_assets;
234   switch (format) {
235     case FORMAT_APK: {
236         auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
237                                                   ZipAssetsProvider::Create(path.c_str(),
238                                                                             property_flags));
239         apk_assets = ApkAssets::Load(std::move(assets), property_flags);
240         break;
241     }
242     case FORMAT_IDMAP:
243       apk_assets = ApkAssets::LoadOverlay(path.c_str(), property_flags);
244       break;
245     case FORMAT_ARSC:
246       apk_assets = ApkAssets::LoadTable(AssetsProvider::CreateAssetFromFile(path.c_str()),
247                                         std::move(loader_assets),
248                                         property_flags);
249       break;
250     case FORMAT_DIRECTORY: {
251       auto assets = MultiAssetsProvider::Create(std::move(loader_assets),
252                                                 DirectoryAssetsProvider::Create(path.c_str()));
253       apk_assets = ApkAssets::Load(std::move(assets), property_flags);
254       break;
255     }
256     default:
257       const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
258       jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
259       return 0;
260   }
261 
262   if (apk_assets == nullptr) {
263     const std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str());
264     jniThrowException(env, "java/io/IOException", error_msg.c_str());
265     return 0;
266   }
267   return CreateGuardedApkAssets(std::move(apk_assets));
268 }
269 
270 #if defined(_WIN32)
DupFdCloExec(int fd)271 int DupFdCloExec(int fd) {
272     int newfd = dup(fd);
273     fprintf(stderr, "duping %d to %d", fd, newfd);
274     return newfd;
275 }
276 #else
DupFdCloExec(int fd)277 int DupFdCloExec(int fd) {
278     int newfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
279     fprintf(stderr, "duping %d to %d", fd, newfd);
280     return newfd;
281 }
282 #endif
283 
NativeLoadFromFd(JNIEnv * env,jclass,const format_type_t format,jobject file_descriptor,jstring friendly_name,const jint property_flags,jobject assets_provider)284 static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, const format_type_t format,
285                               jobject file_descriptor, jstring friendly_name,
286                               const jint property_flags, jobject assets_provider) {
287   ScopedUtfChars friendly_name_utf8(env, friendly_name);
288   if (friendly_name_utf8.c_str() == nullptr) {
289     return 0;
290   }
291 
292   ATRACE_NAME(base::StringPrintf("LoadApkAssetsFd(%s)", friendly_name_utf8.c_str()).c_str());
293 
294   int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
295   if (fd < 0) {
296     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
297     return 0;
298   }
299 
300   unique_fd dup_fd(DupFdCloExec(fd));
301   if (dup_fd < 0) {
302     jniThrowIOException(env, errno);
303     return 0;
304   }
305 
306   auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
307   AssetManager2::ApkAssetsPtr apk_assets;
308   switch (format) {
309     case FORMAT_APK: {
310         auto assets =
311                 MultiAssetsProvider::Create(std::move(loader_assets),
312                                             ZipAssetsProvider::Create(std::move(dup_fd),
313                                                                       friendly_name_utf8.c_str(),
314                                                                       property_flags));
315         apk_assets = ApkAssets::Load(std::move(assets), property_flags);
316         break;
317     }
318     case FORMAT_ARSC:
319       apk_assets = ApkAssets::LoadTable(
320           AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */),
321           std::move(loader_assets), property_flags);
322       break;
323     default:
324       const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
325       jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
326       return 0;
327   }
328 
329   if (apk_assets == nullptr) {
330     std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
331                                                friendly_name_utf8.c_str(), fd);
332     jniThrowException(env, "java/io/IOException", error_msg.c_str());
333     return 0;
334   }
335   return CreateGuardedApkAssets(std::move(apk_assets));
336 }
337 
NativeLoadFromFdOffset(JNIEnv * env,jclass,const format_type_t format,jobject file_descriptor,jstring friendly_name,const jlong offset,const jlong length,const jint property_flags,jobject assets_provider)338 static jlong NativeLoadFromFdOffset(JNIEnv* env, jclass /*clazz*/, const format_type_t format,
339                                     jobject file_descriptor, jstring friendly_name,
340                                     const jlong offset, const jlong length,
341                                     const jint property_flags, jobject assets_provider) {
342   ScopedUtfChars friendly_name_utf8(env, friendly_name);
343   if (friendly_name_utf8.c_str() == nullptr) {
344     return 0;
345   }
346 
347   ATRACE_NAME(base::StringPrintf("LoadApkAssetsFd(%s)", friendly_name_utf8.c_str()).c_str());
348 
349   if (offset < 0) {
350     jniThrowException(env, "java/lang/IllegalArgumentException",
351                      "offset cannot be negative");
352     return 0;
353   }
354 
355   if (length < 0) {
356     jniThrowException(env, "java/lang/IllegalArgumentException",
357                      "length cannot be negative");
358     return 0;
359   }
360 
361   int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
362   if (fd < 0) {
363     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
364     return 0;
365   }
366 
367   unique_fd dup_fd(DupFdCloExec(fd));
368   if (dup_fd < 0) {
369     jniThrowIOException(env, errno);
370     return 0;
371   }
372 
373   auto loader_assets = LoaderAssetsProvider::Create(env, assets_provider);
374   AssetManager2::ApkAssetsPtr apk_assets;
375   switch (format) {
376     case FORMAT_APK: {
377         auto assets =
378                 MultiAssetsProvider::Create(std::move(loader_assets),
379                                             ZipAssetsProvider::Create(std::move(dup_fd),
380                                                                       friendly_name_utf8.c_str(),
381                                                                       property_flags,
382                                                                       static_cast<off64_t>(offset),
383                                                                       static_cast<off64_t>(
384                                                                               length)));
385         apk_assets = ApkAssets::Load(std::move(assets), property_flags);
386         break;
387     }
388     case FORMAT_ARSC:
389       apk_assets = ApkAssets::LoadTable(
390           AssetsProvider::CreateAssetFromFd(std::move(dup_fd), nullptr /* path */,
391                                             static_cast<off64_t>(offset),
392                                             static_cast<off64_t>(length)),
393           std::move(loader_assets), property_flags);
394       break;
395     default:
396       const std::string error_msg = base::StringPrintf("Unsupported format type %d", format);
397       jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
398       return 0;
399   }
400 
401   if (apk_assets == nullptr) {
402     std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
403                                                friendly_name_utf8.c_str(), fd);
404     jniThrowException(env, "java/io/IOException", error_msg.c_str());
405     return 0;
406   }
407   return CreateGuardedApkAssets(std::move(apk_assets));
408 }
409 
NativeLoadEmpty(JNIEnv * env,jclass,jint flags,jobject assets_provider)410 static jlong NativeLoadEmpty(JNIEnv* env, jclass /*clazz*/, jint flags, jobject assets_provider) {
411   auto apk_assets = ApkAssets::Load(LoaderAssetsProvider::Create(env, assets_provider), flags);
412   if (apk_assets == nullptr) {
413     const std::string error_msg =
414         base::StringPrintf("Failed to load empty assets with provider %p", (void*)assets_provider);
415     jniThrowException(env, "java/io/IOException", error_msg.c_str());
416     return 0;
417   }
418   return CreateGuardedApkAssets(std::move(apk_assets));
419 }
420 
NativeDestroy(JNIEnv *,jclass,jlong ptr)421 static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
422   DeleteGuardedApkAssets(ApkAssetsFromLong(ptr));
423 }
424 
NativeGetAssetPath(JNIEnv * env,jclass,jlong ptr)425 static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
426     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
427     auto apk_assets = scoped_apk_assets->get();
428     if (auto path = apk_assets->GetPath()) {
429         return env->NewStringUTF(path->data());
430   }
431   return nullptr;
432 }
433 
NativeGetDebugName(JNIEnv * env,jclass,jlong ptr)434 static jstring NativeGetDebugName(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
435     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
436     auto apk_assets = scoped_apk_assets->get();
437     return env->NewStringUTF(apk_assets->GetDebugName().c_str());
438 }
439 
NativeGetStringBlock(JNIEnv *,jclass,jlong ptr)440 static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
441     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
442     auto apk_assets = scoped_apk_assets->get();
443     return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
444 }
445 
NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr)446 static jboolean NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) {
447     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
448     auto apk_assets = scoped_apk_assets->get();
449     return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE;
450 }
451 
NativeOpenXml(JNIEnv * env,jclass,jlong ptr,jstring file_name)452 static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
453   ScopedUtfChars path_utf8(env, file_name);
454   if (path_utf8.c_str() == nullptr) {
455     return 0;
456   }
457 
458   auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
459   auto apk_assets = scoped_apk_assets->get();
460   std::unique_ptr<Asset> asset = apk_assets->GetAssetsProvider()->Open(
461       path_utf8.c_str(),Asset::AccessMode::ACCESS_RANDOM);
462   if (asset == nullptr) {
463     jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
464     return 0;
465   }
466 
467   const auto buffer = asset->getIncFsBuffer(true /* aligned */);
468   const size_t length = asset->getLength();
469   if (!buffer.convert<uint8_t>().verify(length)) {
470       jniThrowException(env, "java/io/FileNotFoundException",
471                         "File not fully present due to incremental installation");
472       return 0;
473   }
474 
475   // DynamicRefTable is only needed when looking up resource references. Opening an XML file
476   // directly from an ApkAssets has no notion of proper resource references.
477   auto xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
478   status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
479   if (err != NO_ERROR) {
480     jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
481     return 0;
482   }
483   return reinterpret_cast<jlong>(xml_tree.release());
484 }
485 
NativeGetOverlayableInfo(JNIEnv * env,jclass,jlong ptr,jstring overlayable_name)486 static jobject NativeGetOverlayableInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
487                                          jstring overlayable_name) {
488     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
489     auto apk_assets = scoped_apk_assets->get();
490 
491     const auto& packages = apk_assets->GetLoadedArsc()->GetPackages();
492     if (packages.empty()) {
493         jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
494         return 0;
495   }
496 
497   // TODO(b/119899133): Convert this to a search for the info rather than assuming it's at index 0
498   const auto& overlayable_map = packages[0]->GetOverlayableMap();
499   if (overlayable_map.empty()) {
500     return nullptr;
501   }
502 
503   const char* overlayable_name_native = env->GetStringUTFChars(overlayable_name, nullptr);
504   if (overlayable_name_native == nullptr) {
505       return nullptr;
506   }
507   auto actor = overlayable_map.find(overlayable_name_native);
508   env->ReleaseStringUTFChars(overlayable_name, overlayable_name_native);
509   if (actor == overlayable_map.end()) {
510     return nullptr;
511   }
512 
513   jstring actor_string = env->NewStringUTF(actor->second.c_str());
514   if (env->ExceptionCheck() || actor_string == nullptr) {
515     jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
516     return 0;
517   }
518 
519   return env->NewObject(
520       gOverlayableInfoOffsets.classObject,
521       gOverlayableInfoOffsets.constructor,
522       overlayable_name,
523       actor_string
524   );
525 }
526 
NativeDefinesOverlayable(JNIEnv * env,jclass,jlong ptr)527 static jboolean NativeDefinesOverlayable(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
528     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
529     auto apk_assets = scoped_apk_assets->get();
530 
531     const auto& packages = apk_assets->GetLoadedArsc()->GetPackages();
532     if (packages.empty()) {
533         // Must throw to prevent bypass by returning false
534         jniThrowException(env, "java/io/IOException", "Error reading overlayable from APK");
535         return 0;
536   }
537 
538   const auto& overlayable_infos = packages[0]->GetOverlayableMap();
539   return overlayable_infos.empty() ? JNI_FALSE : JNI_TRUE;
540 }
541 
542 // JNI registration.
543 static const JNINativeMethod gApkAssetsMethods[] = {
544         {"nativeLoad", "(ILjava/lang/String;ILandroid/content/res/loader/AssetsProvider;)J",
545          (void*)NativeLoad},
546         {"nativeLoadEmpty", "(ILandroid/content/res/loader/AssetsProvider;)J",
547          (void*)NativeLoadEmpty},
548         {"nativeLoadFd",
549          "(ILjava/io/FileDescriptor;Ljava/lang/String;ILandroid/content/res/loader/"
550          "AssetsProvider;)J",
551          (void*)NativeLoadFromFd},
552         {"nativeLoadFdOffsets",
553          "(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/"
554          "AssetsProvider;)J",
555          (void*)NativeLoadFromFdOffset},
556         {"nativeDestroy", "(J)V", (void*)NativeDestroy},
557         {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
558         {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
559         {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
560         // @CriticalNative
561         {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
562         {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
563         {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;",
564          (void*)NativeGetOverlayableInfo},
565         {"nativeDefinesOverlayable", "(J)Z", (void*)NativeDefinesOverlayable},
566 };
567 
register_android_content_res_ApkAssets(JNIEnv * env)568 int register_android_content_res_ApkAssets(JNIEnv* env) {
569   jclass overlayableInfoClass = FindClassOrDie(env, "android/content/om/OverlayableInfo");
570   gOverlayableInfoOffsets.classObject = MakeGlobalRefOrDie(env, overlayableInfoClass);
571   gOverlayableInfoOffsets.constructor = GetMethodIDOrDie(env, gOverlayableInfoOffsets.classObject,
572       "<init>", "(Ljava/lang/String;Ljava/lang/String;)V");
573 
574   jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
575   gAssetFileDescriptorOffsets.mFd =
576       GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
577   gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
578   gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
579 
580   jclass assetsProvider = FindClassOrDie(env, "android/content/res/loader/AssetsProvider");
581   gAssetsProviderOffsets.classObject = MakeGlobalRefOrDie(env, assetsProvider);
582   gAssetsProviderOffsets.loadAssetFd = GetMethodIDOrDie(
583       env, gAssetsProviderOffsets.classObject, "loadAssetFd",
584       "(Ljava/lang/String;I)Landroid/content/res/AssetFileDescriptor;");
585   gAssetsProviderOffsets.toString = GetMethodIDOrDie(
586       env, gAssetsProviderOffsets.classObject, "toString", "()Ljava/lang/String;");
587 
588   jclass parcelFd = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
589   gParcelFileDescriptorOffsets.detachFd = GetMethodIDOrDie(env, parcelFd, "detachFd", "()I");
590   return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
591                               arraysize(gApkAssetsMethods));
592 }
593 
594 }  // namespace android
595