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