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