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