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