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