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