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