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