1 /*
2  * Copyright 2006, 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 #define LOG_TAG "asset"
19 
20 #include <inttypes.h>
21 #include <linux/capability.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/system_properties.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 
28 #include <private/android_filesystem_config.h> // for AID_SYSTEM
29 
30 #include "android-base/logging.h"
31 #include "android-base/properties.h"
32 #include "android-base/stringprintf.h"
33 #include "android_runtime/android_util_AssetManager.h"
34 #include "android_runtime/AndroidRuntime.h"
35 #include "android_util_Binder.h"
36 #include "androidfw/Asset.h"
37 #include "androidfw/AssetManager.h"
38 #include "androidfw/AssetManager2.h"
39 #include "androidfw/AttributeResolution.h"
40 #include "androidfw/MutexGuard.h"
41 #include "androidfw/ResourceTypes.h"
42 #include "core_jni_helpers.h"
43 #include "jni.h"
44 #include "nativehelper/JNIHelp.h"
45 #include "nativehelper/ScopedPrimitiveArray.h"
46 #include "nativehelper/ScopedStringChars.h"
47 #include "nativehelper/ScopedUtfChars.h"
48 #include "utils/Log.h"
49 #include "utils/misc.h"
50 #include "utils/String8.h"
51 #include "utils/Trace.h"
52 
53 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
54 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
55 
56 using ::android::base::StringPrintf;
57 
58 namespace android {
59 
60 // ----------------------------------------------------------------------------
61 
62 static struct typedvalue_offsets_t {
63   jfieldID mType;
64   jfieldID mData;
65   jfieldID mString;
66   jfieldID mAssetCookie;
67   jfieldID mResourceId;
68   jfieldID mChangingConfigurations;
69   jfieldID mDensity;
70 } gTypedValueOffsets;
71 
72 static struct assetfiledescriptor_offsets_t {
73   jfieldID mFd;
74   jfieldID mStartOffset;
75   jfieldID mLength;
76 } gAssetFileDescriptorOffsets;
77 
78 // This is also used by asset_manager.cpp.
79 assetmanager_offsets_t gAssetManagerOffsets;
80 
81 static struct {
82   jfieldID native_ptr;
83 } gApkAssetsFields;
84 
85 static struct sparsearray_offsets_t {
86   jclass classObject;
87   jmethodID constructor;
88   jmethodID put;
89 } gSparseArrayOffsets;
90 
91 static struct configuration_offsets_t {
92   jclass classObject;
93   jmethodID constructor;
94   jfieldID mSmallestScreenWidthDpOffset;
95   jfieldID mScreenWidthDpOffset;
96   jfieldID mScreenHeightDpOffset;
97 } gConfigurationOffsets;
98 
99 jclass g_stringClass = nullptr;
100 
101 // ----------------------------------------------------------------------------
102 
103 // Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie)104 constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
105   return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
106 }
107 
JavaCookieToApkAssetsCookie(jint cookie)108 constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
109   return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
110 }
111 
112 // This is called by zygote (running as user root) as part of preloadResources.
NativeVerifySystemIdmaps(JNIEnv *,jclass)113 static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
114   switch (pid_t pid = fork()) {
115     case -1:
116       PLOG(ERROR) << "failed to fork for idmap";
117       break;
118 
119     // child
120     case 0: {
121       struct __user_cap_header_struct capheader;
122       struct __user_cap_data_struct capdata;
123 
124       memset(&capheader, 0, sizeof(capheader));
125       memset(&capdata, 0, sizeof(capdata));
126 
127       capheader.version = _LINUX_CAPABILITY_VERSION;
128       capheader.pid = 0;
129 
130       if (capget(&capheader, &capdata) != 0) {
131         PLOG(ERROR) << "capget";
132         exit(1);
133       }
134 
135       capdata.effective = capdata.permitted;
136       if (capset(&capheader, &capdata) != 0) {
137         PLOG(ERROR) << "capset";
138         exit(1);
139       }
140 
141       if (setgid(AID_SYSTEM) != 0) {
142         PLOG(ERROR) << "setgid";
143         exit(1);
144       }
145 
146       if (setuid(AID_SYSTEM) != 0) {
147         PLOG(ERROR) << "setuid";
148         exit(1);
149       }
150 
151       // Generic idmap parameters
152       const char* argv[8];
153       int argc = 0;
154       struct stat st;
155 
156       memset(argv, 0, sizeof(argv));
157       argv[argc++] = AssetManager::IDMAP_BIN;
158       argv[argc++] = "--scan";
159       argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
160       argv[argc++] = AssetManager::TARGET_APK_PATH;
161       argv[argc++] = AssetManager::IDMAP_DIR;
162 
163       // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
164       // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
165       std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
166                                                          "");
167       if (!overlay_theme_path.empty()) {
168         overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
169         if (stat(overlay_theme_path.c_str(), &st) == 0) {
170           argv[argc++] = overlay_theme_path.c_str();
171         }
172       }
173 
174       if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
175         argv[argc++] = AssetManager::OVERLAY_DIR;
176       }
177 
178       if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
179         argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
180       }
181 
182       // Finally, invoke idmap (if any overlay directory exists)
183       if (argc > 5) {
184         execv(AssetManager::IDMAP_BIN, (char* const*)argv);
185         PLOG(ERROR) << "failed to execv for idmap";
186         exit(1); // should never get here
187       } else {
188         exit(0);
189       }
190   } break;
191 
192   // parent
193   default:
194     waitpid(pid, nullptr, 0);
195     break;
196   }
197 }
198 
CopyValue(JNIEnv * env,ApkAssetsCookie cookie,const Res_value & value,uint32_t ref,uint32_t type_spec_flags,ResTable_config * config,jobject out_typed_value)199 static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
200                       uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
201   env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
202   env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
203                    ApkAssetsCookieToJavaCookie(cookie));
204   env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
205   env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
206   env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
207   env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
208   if (config != nullptr) {
209     env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
210   }
211   return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
212 }
213 
214 // ----------------------------------------------------------------------------
215 
216 // Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
217 struct GuardedAssetManager : public ::AAssetManager {
218   Guarded<AssetManager2> guarded_assetmanager;
219 };
220 
NdkAssetManagerForJavaObject(JNIEnv * env,jobject jassetmanager)221 ::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
222   jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
223   ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
224   if (am == nullptr) {
225     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
226     return nullptr;
227   }
228   return am;
229 }
230 
AssetManagerForNdkAssetManager(::AAssetManager * assetmanager)231 Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
232   if (assetmanager == nullptr) {
233     return nullptr;
234   }
235   return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
236 }
237 
AssetManagerForJavaObject(JNIEnv * env,jobject jassetmanager)238 Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
239   return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
240 }
241 
AssetManagerFromLong(jlong ptr)242 static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
243   return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
244 }
245 
ReturnParcelFileDescriptor(JNIEnv * env,std::unique_ptr<Asset> asset,jlongArray out_offsets)246 static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
247                                           jlongArray out_offsets) {
248   off64_t start_offset, length;
249   int fd = asset->openFileDescriptor(&start_offset, &length);
250   asset.reset();
251 
252   if (fd < 0) {
253     jniThrowException(env, "java/io/FileNotFoundException",
254                       "This file can not be opened as a file descriptor; it is probably "
255                       "compressed");
256     return nullptr;
257   }
258 
259   jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
260   if (offsets == nullptr) {
261     close(fd);
262     return nullptr;
263   }
264 
265   offsets[0] = start_offset;
266   offsets[1] = length;
267 
268   env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
269 
270   jobject file_desc = jniCreateFileDescriptor(env, fd);
271   if (file_desc == nullptr) {
272     close(fd);
273     return nullptr;
274   }
275   return newParcelFileDescriptor(env, file_desc);
276 }
277 
NativeGetGlobalAssetCount(JNIEnv *,jobject)278 static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
279   return Asset::getGlobalCount();
280 }
281 
NativeGetAssetAllocations(JNIEnv * env,jobject)282 static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
283   String8 alloc = Asset::getAssetAllocations();
284   if (alloc.length() <= 0) {
285     return nullptr;
286   }
287   return env->NewStringUTF(alloc.string());
288 }
289 
NativeGetGlobalAssetManagerCount(JNIEnv *,jobject)290 static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
291   // TODO(adamlesinski): Switch to AssetManager2.
292   return AssetManager::getGlobalCount();
293 }
294 
NativeCreate(JNIEnv *,jclass)295 static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
296   // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
297   // AssetManager2 in a contiguous block (GuardedAssetManager).
298   return reinterpret_cast<jlong>(new GuardedAssetManager());
299 }
300 
NativeDestroy(JNIEnv *,jclass,jlong ptr)301 static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
302   delete reinterpret_cast<GuardedAssetManager*>(ptr);
303 }
304 
NativeSetApkAssets(JNIEnv * env,jclass,jlong ptr,jobjectArray apk_assets_array,jboolean invalidate_caches)305 static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
306                                jobjectArray apk_assets_array, jboolean invalidate_caches) {
307   ATRACE_NAME("AssetManager::SetApkAssets");
308 
309   const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
310   std::vector<const ApkAssets*> apk_assets;
311   apk_assets.reserve(apk_assets_len);
312   for (jsize i = 0; i < apk_assets_len; i++) {
313     jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
314     if (obj == nullptr) {
315       std::string msg = StringPrintf("ApkAssets at index %d is null", i);
316       jniThrowNullPointerException(env, msg.c_str());
317       return;
318     }
319 
320     jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
321     if (env->ExceptionCheck()) {
322       return;
323     }
324     apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
325   }
326 
327   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
328   assetmanager->SetApkAssets(apk_assets, invalidate_caches);
329 }
330 
NativeSetConfiguration(JNIEnv * env,jclass,jlong ptr,jint mcc,jint mnc,jstring locale,jint orientation,jint touchscreen,jint density,jint keyboard,jint keyboard_hidden,jint navigation,jint screen_width,jint screen_height,jint smallest_screen_width_dp,jint screen_width_dp,jint screen_height_dp,jint screen_layout,jint ui_mode,jint color_mode,jint major_version)331 static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
332                                    jstring locale, jint orientation, jint touchscreen, jint density,
333                                    jint keyboard, jint keyboard_hidden, jint navigation,
334                                    jint screen_width, jint screen_height,
335                                    jint smallest_screen_width_dp, jint screen_width_dp,
336                                    jint screen_height_dp, jint screen_layout, jint ui_mode,
337                                    jint color_mode, jint major_version) {
338   ATRACE_NAME("AssetManager::SetConfiguration");
339 
340   ResTable_config configuration;
341   memset(&configuration, 0, sizeof(configuration));
342   configuration.mcc = static_cast<uint16_t>(mcc);
343   configuration.mnc = static_cast<uint16_t>(mnc);
344   configuration.orientation = static_cast<uint8_t>(orientation);
345   configuration.touchscreen = static_cast<uint8_t>(touchscreen);
346   configuration.density = static_cast<uint16_t>(density);
347   configuration.keyboard = static_cast<uint8_t>(keyboard);
348   configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
349   configuration.navigation = static_cast<uint8_t>(navigation);
350   configuration.screenWidth = static_cast<uint16_t>(screen_width);
351   configuration.screenHeight = static_cast<uint16_t>(screen_height);
352   configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
353   configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
354   configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
355   configuration.screenLayout = static_cast<uint8_t>(screen_layout);
356   configuration.uiMode = static_cast<uint8_t>(ui_mode);
357   configuration.colorMode = static_cast<uint8_t>(color_mode);
358   configuration.sdkVersion = static_cast<uint16_t>(major_version);
359 
360   if (locale != nullptr) {
361     ScopedUtfChars locale_utf8(env, locale);
362     CHECK(locale_utf8.c_str() != nullptr);
363     configuration.setBcp47Locale(locale_utf8.c_str());
364   }
365 
366   // Constants duplicated from Java class android.content.res.Configuration.
367   static const jint kScreenLayoutRoundMask = 0x300;
368   static const jint kScreenLayoutRoundShift = 8;
369 
370   // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
371   // in C++. We must extract the round qualifier out of the Java screenLayout and put it
372   // into screenLayout2.
373   configuration.screenLayout2 =
374       static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
375 
376   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
377   assetmanager->SetConfiguration(configuration);
378 }
379 
NativeGetAssignedPackageIdentifiers(JNIEnv * env,jclass,jlong ptr)380 static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
381   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
382 
383   jobject sparse_array =
384         env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
385 
386   if (sparse_array == nullptr) {
387     // An exception is pending.
388     return nullptr;
389   }
390 
391   assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
392     jstring jpackage_name = env->NewStringUTF(package_name.c_str());
393     if (jpackage_name == nullptr) {
394       // An exception is pending.
395       return;
396     }
397 
398     env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
399                         jpackage_name);
400   });
401   return sparse_array;
402 }
403 
NativeList(JNIEnv * env,jclass,jlong ptr,jstring path)404 static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
405   ScopedUtfChars path_utf8(env, path);
406   if (path_utf8.c_str() == nullptr) {
407     // This will throw NPE.
408     return nullptr;
409   }
410 
411   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
412   std::unique_ptr<AssetDir> asset_dir =
413       assetmanager->OpenDir(path_utf8.c_str());
414   if (asset_dir == nullptr) {
415     jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
416     return nullptr;
417   }
418 
419   const size_t file_count = asset_dir->getFileCount();
420 
421   jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
422   if (array == nullptr) {
423     return nullptr;
424   }
425 
426   for (size_t i = 0; i < file_count; i++) {
427     jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
428 
429     // Check for errors creating the strings (if malformed or no memory).
430     if (env->ExceptionCheck()) {
431      return nullptr;
432     }
433 
434     env->SetObjectArrayElement(array, i, java_string);
435 
436     // If we have a large amount of string in our array, we might overflow the
437     // local reference table of the VM.
438     env->DeleteLocalRef(java_string);
439   }
440   return array;
441 }
442 
NativeOpenAsset(JNIEnv * env,jclass,jlong ptr,jstring asset_path,jint access_mode)443 static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
444                              jint access_mode) {
445   ScopedUtfChars asset_path_utf8(env, asset_path);
446   if (asset_path_utf8.c_str() == nullptr) {
447     // This will throw NPE.
448     return 0;
449   }
450 
451   ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
452 
453   if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
454       access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
455     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
456     return 0;
457   }
458 
459   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
460   std::unique_ptr<Asset> asset =
461       assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
462   if (!asset) {
463     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
464     return 0;
465   }
466   return reinterpret_cast<jlong>(asset.release());
467 }
468 
NativeOpenAssetFd(JNIEnv * env,jclass,jlong ptr,jstring asset_path,jlongArray out_offsets)469 static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
470                                  jlongArray out_offsets) {
471   ScopedUtfChars asset_path_utf8(env, asset_path);
472   if (asset_path_utf8.c_str() == nullptr) {
473     // This will throw NPE.
474     return nullptr;
475   }
476 
477   ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
478 
479   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
480   std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
481   if (!asset) {
482     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
483     return nullptr;
484   }
485   return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
486 }
487 
NativeOpenNonAsset(JNIEnv * env,jclass,jlong ptr,jint jcookie,jstring asset_path,jint access_mode)488 static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
489                                 jstring asset_path, jint access_mode) {
490   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
491   ScopedUtfChars asset_path_utf8(env, asset_path);
492   if (asset_path_utf8.c_str() == nullptr) {
493     // This will throw NPE.
494     return 0;
495   }
496 
497   ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
498 
499   if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
500       access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
501     jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
502     return 0;
503   }
504 
505   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
506   std::unique_ptr<Asset> asset;
507   if (cookie != kInvalidCookie) {
508     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
509                                        static_cast<Asset::AccessMode>(access_mode));
510   } else {
511     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
512                                        static_cast<Asset::AccessMode>(access_mode));
513   }
514 
515   if (!asset) {
516     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
517     return 0;
518   }
519   return reinterpret_cast<jlong>(asset.release());
520 }
521 
NativeOpenNonAssetFd(JNIEnv * env,jclass,jlong ptr,jint jcookie,jstring asset_path,jlongArray out_offsets)522 static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
523                                     jstring asset_path, jlongArray out_offsets) {
524   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
525   ScopedUtfChars asset_path_utf8(env, asset_path);
526   if (asset_path_utf8.c_str() == nullptr) {
527     // This will throw NPE.
528     return nullptr;
529   }
530 
531   ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
532 
533   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
534   std::unique_ptr<Asset> asset;
535   if (cookie != kInvalidCookie) {
536     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
537   } else {
538     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
539   }
540 
541   if (!asset) {
542     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
543     return nullptr;
544   }
545   return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
546 }
547 
NativeOpenXmlAsset(JNIEnv * env,jobject,jlong ptr,jint jcookie,jstring asset_path)548 static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
549                                 jstring asset_path) {
550   ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
551   ScopedUtfChars asset_path_utf8(env, asset_path);
552   if (asset_path_utf8.c_str() == nullptr) {
553     // This will throw NPE.
554     return 0;
555   }
556 
557   ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
558 
559   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
560   std::unique_ptr<Asset> asset;
561   if (cookie != kInvalidCookie) {
562     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
563   } else {
564     asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
565   }
566 
567   if (!asset) {
568     jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
569     return 0;
570   }
571 
572   // May be nullptr.
573   const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
574 
575   std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
576   status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
577   asset.reset();
578 
579   if (err != NO_ERROR) {
580     jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
581     return 0;
582   }
583   return reinterpret_cast<jlong>(xml_tree.release());
584 }
585 
NativeGetResourceValue(JNIEnv * env,jclass,jlong ptr,jint resid,jshort density,jobject typed_value,jboolean resolve_references)586 static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
587                                    jshort density, jobject typed_value,
588                                    jboolean resolve_references) {
589   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
590   Res_value value;
591   ResTable_config selected_config;
592   uint32_t flags;
593   ApkAssetsCookie cookie =
594       assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
595                                 static_cast<uint16_t>(density), &value, &selected_config, &flags);
596   if (cookie == kInvalidCookie) {
597     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
598   }
599 
600   uint32_t ref = static_cast<uint32_t>(resid);
601   if (resolve_references) {
602     cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
603     if (cookie == kInvalidCookie) {
604       return ApkAssetsCookieToJavaCookie(kInvalidCookie);
605     }
606   }
607   return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
608 }
609 
NativeGetResourceBagValue(JNIEnv * env,jclass,jlong ptr,jint resid,jint bag_entry_id,jobject typed_value)610 static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
611                                       jint bag_entry_id, jobject typed_value) {
612   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
613   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
614   if (bag == nullptr) {
615     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
616   }
617 
618   uint32_t type_spec_flags = bag->type_spec_flags;
619   ApkAssetsCookie cookie = kInvalidCookie;
620   const Res_value* bag_value = nullptr;
621   for (const ResolvedBag::Entry& entry : bag) {
622     if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
623       cookie = entry.cookie;
624       bag_value = &entry.value;
625 
626       // Keep searching (the old implementation did that).
627     }
628   }
629 
630   if (cookie == kInvalidCookie) {
631     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
632   }
633 
634   Res_value value = *bag_value;
635   uint32_t ref = static_cast<uint32_t>(resid);
636   ResTable_config selected_config;
637   cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
638   if (cookie == kInvalidCookie) {
639     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
640   }
641   return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
642 }
643 
NativeGetStyleAttributes(JNIEnv * env,jclass,jlong ptr,jint resid)644 static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
645   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
646   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
647   if (bag == nullptr) {
648     return nullptr;
649   }
650 
651   jintArray array = env->NewIntArray(bag->entry_count);
652   if (env->ExceptionCheck()) {
653     return nullptr;
654   }
655 
656   for (uint32_t i = 0; i < bag->entry_count; i++) {
657     jint attr_resid = bag->entries[i].key;
658     env->SetIntArrayRegion(array, i, 1, &attr_resid);
659   }
660   return array;
661 }
662 
NativeGetResourceStringArray(JNIEnv * env,jclass,jlong ptr,jint resid)663 static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
664                                                  jint resid) {
665   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
666   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
667   if (bag == nullptr) {
668     return nullptr;
669   }
670 
671   jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
672   if (array == nullptr) {
673     return nullptr;
674   }
675 
676   for (uint32_t i = 0; i < bag->entry_count; i++) {
677     const ResolvedBag::Entry& entry = bag->entries[i];
678 
679     // Resolve any references to their final value.
680     Res_value value = entry.value;
681     ResTable_config selected_config;
682     uint32_t flags;
683     uint32_t ref;
684     ApkAssetsCookie cookie =
685         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
686     if (cookie == kInvalidCookie) {
687       return nullptr;
688     }
689 
690     if (value.dataType == Res_value::TYPE_STRING) {
691       const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
692       const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
693 
694       jstring java_string = nullptr;
695       size_t str_len;
696       const char* str_utf8 = pool->string8At(value.data, &str_len);
697       if (str_utf8 != nullptr) {
698         java_string = env->NewStringUTF(str_utf8);
699       } else {
700         const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
701         java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
702       }
703 
704       // Check for errors creating the strings (if malformed or no memory).
705       if (env->ExceptionCheck()) {
706         return nullptr;
707       }
708 
709       env->SetObjectArrayElement(array, i, java_string);
710 
711       // If we have a large amount of string in our array, we might overflow the
712       // local reference table of the VM.
713       env->DeleteLocalRef(java_string);
714     }
715   }
716   return array;
717 }
718 
NativeGetResourceStringArrayInfo(JNIEnv * env,jclass,jlong ptr,jint resid)719 static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
720                                                   jint resid) {
721   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
722   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
723   if (bag == nullptr) {
724     return nullptr;
725   }
726 
727   jintArray array = env->NewIntArray(bag->entry_count * 2);
728   if (array == nullptr) {
729     return nullptr;
730   }
731 
732   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
733   if (buffer == nullptr) {
734     return nullptr;
735   }
736 
737   for (size_t i = 0; i < bag->entry_count; i++) {
738     const ResolvedBag::Entry& entry = bag->entries[i];
739     Res_value value = entry.value;
740     ResTable_config selected_config;
741     uint32_t flags;
742     uint32_t ref;
743     ApkAssetsCookie cookie =
744         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
745     if (cookie == kInvalidCookie) {
746       env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
747       return nullptr;
748     }
749 
750     jint string_index = -1;
751     if (value.dataType == Res_value::TYPE_STRING) {
752       string_index = static_cast<jint>(value.data);
753     }
754 
755     buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
756     buffer[(i * 2) + 1] = string_index;
757   }
758   env->ReleasePrimitiveArrayCritical(array, buffer, 0);
759   return array;
760 }
761 
NativeGetResourceIntArray(JNIEnv * env,jclass,jlong ptr,jint resid)762 static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
763   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
764   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
765   if (bag == nullptr) {
766     return nullptr;
767   }
768 
769   jintArray array = env->NewIntArray(bag->entry_count);
770   if (array == nullptr) {
771     return nullptr;
772   }
773 
774   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
775   if (buffer == nullptr) {
776     return nullptr;
777   }
778 
779   for (size_t i = 0; i < bag->entry_count; i++) {
780     const ResolvedBag::Entry& entry = bag->entries[i];
781     Res_value value = entry.value;
782     ResTable_config selected_config;
783     uint32_t flags;
784     uint32_t ref;
785     ApkAssetsCookie cookie =
786         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
787     if (cookie == kInvalidCookie) {
788       env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
789       return nullptr;
790     }
791 
792     if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
793       buffer[i] = static_cast<jint>(value.data);
794     }
795   }
796   env->ReleasePrimitiveArrayCritical(array, buffer, 0);
797   return array;
798 }
799 
NativeGetResourceArraySize(JNIEnv *,jclass,jlong ptr,jint resid)800 static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
801   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
802   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
803   if (bag == nullptr) {
804     return -1;
805   }
806   return static_cast<jint>(bag->entry_count);
807 }
808 
NativeGetResourceArray(JNIEnv * env,jclass,jlong ptr,jint resid,jintArray out_data)809 static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
810                                    jintArray out_data) {
811   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
812   const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
813   if (bag == nullptr) {
814     return -1;
815   }
816 
817   const jsize out_data_length = env->GetArrayLength(out_data);
818   if (env->ExceptionCheck()) {
819     return -1;
820   }
821 
822   if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
823     jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
824     return -1;
825   }
826 
827   jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
828   if (buffer == nullptr) {
829     return -1;
830   }
831 
832   jint* cursor = buffer;
833   for (size_t i = 0; i < bag->entry_count; i++) {
834     const ResolvedBag::Entry& entry = bag->entries[i];
835     Res_value value = entry.value;
836     ResTable_config selected_config;
837     selected_config.density = 0;
838     uint32_t flags = bag->type_spec_flags;
839     uint32_t ref = 0;
840     ApkAssetsCookie cookie =
841         assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
842     if (cookie == kInvalidCookie) {
843       env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
844       return -1;
845     }
846 
847     // Deal with the special @null value -- it turns back to TYPE_NULL.
848     if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
849       value.dataType = Res_value::TYPE_NULL;
850       value.data = Res_value::DATA_NULL_UNDEFINED;
851     }
852 
853     cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
854     cursor[STYLE_DATA] = static_cast<jint>(value.data);
855     cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
856     cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
857     cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
858     cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
859     cursor += STYLE_NUM_ENTRIES;
860   }
861   env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
862   return static_cast<jint>(bag->entry_count);
863 }
864 
NativeGetResourceIdentifier(JNIEnv * env,jclass,jlong ptr,jstring name,jstring def_type,jstring def_package)865 static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
866                                         jstring def_type, jstring def_package) {
867   ScopedUtfChars name_utf8(env, name);
868   if (name_utf8.c_str() == nullptr) {
869     // This will throw NPE.
870     return 0;
871   }
872 
873   std::string type;
874   if (def_type != nullptr) {
875     ScopedUtfChars type_utf8(env, def_type);
876     CHECK(type_utf8.c_str() != nullptr);
877     type = type_utf8.c_str();
878   }
879 
880   std::string package;
881   if (def_package != nullptr) {
882     ScopedUtfChars package_utf8(env, def_package);
883     CHECK(package_utf8.c_str() != nullptr);
884     package = package_utf8.c_str();
885   }
886   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
887   return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
888 }
889 
NativeGetResourceName(JNIEnv * env,jclass,jlong ptr,jint resid)890 static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
891   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
892   AssetManager2::ResourceName name;
893   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
894     return nullptr;
895   }
896 
897   std::string result;
898   if (name.package != nullptr) {
899     result.append(name.package, name.package_len);
900   }
901 
902   if (name.type != nullptr || name.type16 != nullptr) {
903     if (!result.empty()) {
904       result += ":";
905     }
906 
907     if (name.type != nullptr) {
908       result.append(name.type, name.type_len);
909     } else {
910       result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
911     }
912   }
913 
914   if (name.entry != nullptr || name.entry16 != nullptr) {
915     if (!result.empty()) {
916       result += "/";
917     }
918 
919     if (name.entry != nullptr) {
920       result.append(name.entry, name.entry_len);
921     } else {
922       result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
923     }
924   }
925   return env->NewStringUTF(result.c_str());
926 }
927 
NativeGetResourcePackageName(JNIEnv * env,jclass,jlong ptr,jint resid)928 static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
929   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
930   AssetManager2::ResourceName name;
931   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
932     return nullptr;
933   }
934 
935   if (name.package != nullptr) {
936     return env->NewStringUTF(name.package);
937   }
938   return nullptr;
939 }
940 
NativeGetResourceTypeName(JNIEnv * env,jclass,jlong ptr,jint resid)941 static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
942   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
943   AssetManager2::ResourceName name;
944   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
945     return nullptr;
946   }
947 
948   if (name.type != nullptr) {
949     return env->NewStringUTF(name.type);
950   } else if (name.type16 != nullptr) {
951     return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
952   }
953   return nullptr;
954 }
955 
NativeGetResourceEntryName(JNIEnv * env,jclass,jlong ptr,jint resid)956 static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
957   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
958   AssetManager2::ResourceName name;
959   if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
960     return nullptr;
961   }
962 
963   if (name.entry != nullptr) {
964     return env->NewStringUTF(name.entry);
965   } else if (name.entry16 != nullptr) {
966     return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
967   }
968   return nullptr;
969 }
970 
NativeGetLocales(JNIEnv * env,jclass,jlong ptr,jboolean exclude_system)971 static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
972                                      jboolean exclude_system) {
973   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
974   std::set<std::string> locales =
975       assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
976 
977   jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
978   if (array == nullptr) {
979     return nullptr;
980   }
981 
982   size_t idx = 0;
983   for (const std::string& locale : locales) {
984     jstring java_string = env->NewStringUTF(locale.c_str());
985     if (java_string == nullptr) {
986       return nullptr;
987     }
988     env->SetObjectArrayElement(array, idx++, java_string);
989     env->DeleteLocalRef(java_string);
990   }
991   return array;
992 }
993 
ConstructConfigurationObject(JNIEnv * env,const ResTable_config & config)994 static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
995   jobject result =
996       env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
997   if (result == nullptr) {
998     return nullptr;
999   }
1000 
1001   env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1002                    config.smallestScreenWidthDp);
1003   env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1004   env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1005   return result;
1006 }
1007 
NativeGetSizeConfigurations(JNIEnv * env,jclass,jlong ptr)1008 static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1009   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1010   std::set<ResTable_config> configurations =
1011       assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1012 
1013   jobjectArray array =
1014       env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1015   if (array == nullptr) {
1016     return nullptr;
1017   }
1018 
1019   size_t idx = 0;
1020   for (const ResTable_config& configuration : configurations) {
1021     jobject java_configuration = ConstructConfigurationObject(env, configuration);
1022     if (java_configuration == nullptr) {
1023       return nullptr;
1024     }
1025 
1026     env->SetObjectArrayElement(array, idx++, java_configuration);
1027     env->DeleteLocalRef(java_configuration);
1028   }
1029   return array;
1030 }
1031 
NativeApplyStyle(JNIEnv * env,jclass,jlong ptr,jlong theme_ptr,jint def_style_attr,jint def_style_resid,jlong xml_parser_ptr,jintArray java_attrs,jlong out_values_ptr,jlong out_indices_ptr)1032 static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1033                              jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1034                              jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
1035   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1036   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1037   CHECK(theme->GetAssetManager() == &(*assetmanager));
1038   (void) assetmanager;
1039 
1040   ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1041   uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
1042   uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
1043 
1044   jsize attrs_len = env->GetArrayLength(java_attrs);
1045   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1046   if (attrs == nullptr) {
1047     return;
1048   }
1049 
1050   ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
1051              static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
1052              out_values, out_indices);
1053   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1054 }
1055 
NativeResolveAttrs(JNIEnv * env,jclass,jlong ptr,jlong theme_ptr,jint def_style_attr,jint def_style_resid,jintArray java_values,jintArray java_attrs,jintArray out_java_values,jintArray out_java_indices)1056 static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1057                                    jint def_style_attr, jint def_style_resid, jintArray java_values,
1058                                    jintArray java_attrs, jintArray out_java_values,
1059                                    jintArray out_java_indices) {
1060   const jsize attrs_len = env->GetArrayLength(java_attrs);
1061   const jsize out_values_len = env->GetArrayLength(out_java_values);
1062   if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1063     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1064     return JNI_FALSE;
1065   }
1066 
1067   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1068   if (attrs == nullptr) {
1069     return JNI_FALSE;
1070   }
1071 
1072   jint* values = nullptr;
1073   jsize values_len = 0;
1074   if (java_values != nullptr) {
1075     values_len = env->GetArrayLength(java_values);
1076     values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
1077     if (values == nullptr) {
1078       env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1079       return JNI_FALSE;
1080     }
1081   }
1082 
1083   jint* out_values =
1084       reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1085   if (out_values == nullptr) {
1086     env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1087     if (values != nullptr) {
1088       env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1089     }
1090     return JNI_FALSE;
1091   }
1092 
1093   jint* out_indices = nullptr;
1094   if (out_java_indices != nullptr) {
1095     jsize out_indices_len = env->GetArrayLength(out_java_indices);
1096     if (out_indices_len > attrs_len) {
1097       out_indices =
1098           reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1099       if (out_indices == nullptr) {
1100         env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1101         if (values != nullptr) {
1102           env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1103         }
1104         env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1105         return JNI_FALSE;
1106       }
1107     }
1108   }
1109 
1110   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1111   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1112   CHECK(theme->GetAssetManager() == &(*assetmanager));
1113   (void) assetmanager;
1114 
1115   bool result = ResolveAttrs(
1116       theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1117       reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1118       attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1119   if (out_indices != nullptr) {
1120     env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1121   }
1122 
1123   env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1124   if (values != nullptr) {
1125     env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1126   }
1127   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1128   return result ? JNI_TRUE : JNI_FALSE;
1129 }
1130 
NativeRetrieveAttributes(JNIEnv * env,jclass,jlong ptr,jlong xml_parser_ptr,jintArray java_attrs,jintArray out_java_values,jintArray out_java_indices)1131 static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1132                                          jlong xml_parser_ptr, jintArray java_attrs,
1133                                          jintArray out_java_values, jintArray out_java_indices) {
1134   const jsize attrs_len = env->GetArrayLength(java_attrs);
1135   const jsize out_values_len = env->GetArrayLength(out_java_values);
1136   if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1137     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1138     return JNI_FALSE;
1139   }
1140 
1141   jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1142   if (attrs == nullptr) {
1143     return JNI_FALSE;
1144   }
1145 
1146   jint* out_values =
1147       reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1148   if (out_values == nullptr) {
1149     env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1150     return JNI_FALSE;
1151   }
1152 
1153   jint* out_indices = nullptr;
1154   if (out_java_indices != nullptr) {
1155     jsize out_indices_len = env->GetArrayLength(out_java_indices);
1156     if (out_indices_len > attrs_len) {
1157       out_indices =
1158           reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1159       if (out_indices == nullptr) {
1160         env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1161         env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1162         return JNI_FALSE;
1163       }
1164     }
1165   }
1166 
1167   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1168   ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1169 
1170   bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1171                                    reinterpret_cast<uint32_t*>(attrs), attrs_len,
1172                                    reinterpret_cast<uint32_t*>(out_values),
1173                                    reinterpret_cast<uint32_t*>(out_indices));
1174 
1175   if (out_indices != nullptr) {
1176     env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1177   }
1178   env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1179   env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1180   return result ? JNI_TRUE : JNI_FALSE;
1181 }
1182 
NativeThemeCreate(JNIEnv *,jclass,jlong ptr)1183 static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1184   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1185   return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1186 }
1187 
NativeThemeDestroy(JNIEnv *,jclass,jlong theme_ptr)1188 static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1189   delete reinterpret_cast<Theme*>(theme_ptr);
1190 }
1191 
NativeThemeApplyStyle(JNIEnv * env,jclass,jlong ptr,jlong theme_ptr,jint resid,jboolean force)1192 static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1193                                   jint resid, jboolean force) {
1194   // AssetManager is accessed via the theme, so grab an explicit lock here.
1195   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1196   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1197   CHECK(theme->GetAssetManager() == &(*assetmanager));
1198   (void) assetmanager;
1199   theme->ApplyStyle(static_cast<uint32_t>(resid), force);
1200 
1201   // TODO(adamlesinski): Consider surfacing exception when result is failure.
1202   // CTS currently expects no exceptions from this method.
1203   // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1204   // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
1205 }
1206 
NativeThemeCopy(JNIEnv * env,jclass,jlong dst_theme_ptr,jlong src_theme_ptr)1207 static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
1208                             jlong src_theme_ptr) {
1209   Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1210   Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
1211   if (!dst_theme->SetTo(*src_theme)) {
1212     jniThrowException(env, "java/lang/IllegalArgumentException",
1213                       "Themes are from different AssetManagers");
1214   }
1215 }
1216 
NativeThemeClear(JNIEnv *,jclass,jlong theme_ptr)1217 static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1218   reinterpret_cast<Theme*>(theme_ptr)->Clear();
1219 }
1220 
NativeThemeGetAttributeValue(JNIEnv * env,jclass,jlong ptr,jlong theme_ptr,jint resid,jobject typed_value,jboolean resolve_references)1221 static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1222                                          jint resid, jobject typed_value,
1223                                          jboolean resolve_references) {
1224   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1225   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1226   CHECK(theme->GetAssetManager() == &(*assetmanager));
1227   (void) assetmanager;
1228 
1229   Res_value value;
1230   uint32_t flags;
1231   ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1232   if (cookie == kInvalidCookie) {
1233     return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1234   }
1235 
1236   uint32_t ref = 0u;
1237   if (resolve_references) {
1238     ResTable_config selected_config;
1239     cookie =
1240         theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1241     if (cookie == kInvalidCookie) {
1242       return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1243     }
1244   }
1245   return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1246 }
1247 
NativeThemeDump(JNIEnv *,jclass,jlong ptr,jlong theme_ptr,jint priority,jstring tag,jstring prefix)1248 static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1249                             jint priority, jstring tag, jstring prefix) {
1250   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1251   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1252   CHECK(theme->GetAssetManager() == &(*assetmanager));
1253   (void) assetmanager;
1254   (void) theme;
1255   (void) priority;
1256   (void) tag;
1257   (void) prefix;
1258 }
1259 
NativeThemeGetChangingConfigurations(JNIEnv *,jclass,jlong theme_ptr)1260 static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1261                                                  jlong theme_ptr) {
1262   Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1263   return static_cast<jint>(theme->GetChangingConfigurations());
1264 }
1265 
NativeAssetDestroy(JNIEnv *,jclass,jlong asset_ptr)1266 static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1267   delete reinterpret_cast<Asset*>(asset_ptr);
1268 }
1269 
NativeAssetReadChar(JNIEnv *,jclass,jlong asset_ptr)1270 static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1271   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1272   uint8_t b;
1273   ssize_t res = asset->read(&b, sizeof(b));
1274   return res == sizeof(b) ? static_cast<jint>(b) : -1;
1275 }
1276 
NativeAssetRead(JNIEnv * env,jclass,jlong asset_ptr,jbyteArray java_buffer,jint offset,jint len)1277 static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1278                             jint offset, jint len) {
1279   if (len == 0) {
1280     return 0;
1281   }
1282 
1283   jsize buffer_len = env->GetArrayLength(java_buffer);
1284   if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1285       offset > buffer_len - len) {
1286     jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1287     return -1;
1288   }
1289 
1290   ScopedByteArrayRW byte_array(env, java_buffer);
1291   if (byte_array.get() == nullptr) {
1292     return -1;
1293   }
1294 
1295   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1296   ssize_t res = asset->read(byte_array.get() + offset, len);
1297   if (res < 0) {
1298     jniThrowException(env, "java/io/IOException", "");
1299     return -1;
1300   }
1301   return res > 0 ? static_cast<jint>(res) : -1;
1302 }
1303 
NativeAssetSeek(JNIEnv * env,jclass,jlong asset_ptr,jlong offset,jint whence)1304 static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1305                              jint whence) {
1306   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1307   return static_cast<jlong>(asset->seek(
1308       static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1309 }
1310 
NativeAssetGetLength(JNIEnv *,jclass,jlong asset_ptr)1311 static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1312   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1313   return static_cast<jlong>(asset->getLength());
1314 }
1315 
NativeAssetGetRemainingLength(JNIEnv *,jclass,jlong asset_ptr)1316 static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1317   Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1318   return static_cast<jlong>(asset->getRemainingLength());
1319 }
1320 
1321 // ----------------------------------------------------------------------------
1322 
1323 // JNI registration.
1324 static const JNINativeMethod gAssetManagerMethods[] = {
1325     // AssetManager setup methods.
1326     {"nativeCreate", "()J", (void*)NativeCreate},
1327     {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1328     {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1329     {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1330      (void*)NativeSetConfiguration},
1331     {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
1332      (void*)NativeGetAssignedPackageIdentifiers},
1333 
1334     // AssetManager file methods.
1335     {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1336     {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1337     {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1338      (void*)NativeOpenAssetFd},
1339     {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1340     {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1341      (void*)NativeOpenNonAssetFd},
1342     {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
1343 
1344     // AssetManager resource methods.
1345     {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1346     {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1347      (void*)NativeGetResourceBagValue},
1348     {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1349     {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1350      (void*)NativeGetResourceStringArray},
1351     {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1352     {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1353     {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1354     {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1355 
1356     // AssetManager resource name/ID methods.
1357     {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1358      (void*)NativeGetResourceIdentifier},
1359     {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1360     {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1361     {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1362     {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
1363     {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1364     {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1365      (void*)NativeGetSizeConfigurations},
1366 
1367     // Style attribute related methods.
1368     {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1369     {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1370     {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1371 
1372     // Theme related methods.
1373     {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1374     {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1375     {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
1376     {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
1377     {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1378     {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1379      (void*)NativeThemeGetAttributeValue},
1380     {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1381     {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1382 
1383     // AssetInputStream methods.
1384     {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1385     {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1386     {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1387     {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1388     {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1389     {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1390 
1391     // System/idmap related methods.
1392     {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
1393 
1394     // Global management/debug methods.
1395     {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1396     {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1397     {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1398 };
1399 
register_android_content_AssetManager(JNIEnv * env)1400 int register_android_content_AssetManager(JNIEnv* env) {
1401   jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1402   gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1403 
1404   jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1405   gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1406   gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1407   gTypedValueOffsets.mString =
1408       GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1409   gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1410   gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1411   gTypedValueOffsets.mChangingConfigurations =
1412       GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1413   gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1414 
1415   jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1416   gAssetFileDescriptorOffsets.mFd =
1417       GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1418   gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1419   gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1420 
1421   jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1422   gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1423 
1424   jclass stringClass = FindClassOrDie(env, "java/lang/String");
1425   g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1426 
1427   jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1428   gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1429   gSparseArrayOffsets.constructor =
1430       GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1431   gSparseArrayOffsets.put =
1432       GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1433 
1434   jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1435   gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1436   gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1437   gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1438       GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1439   gConfigurationOffsets.mScreenWidthDpOffset =
1440       GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1441   gConfigurationOffsets.mScreenHeightDpOffset =
1442       GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1443 
1444   return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1445                               NELEM(gAssetManagerMethods));
1446 }
1447 
1448 }; // namespace android
1449