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