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