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