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