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