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