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