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