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