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