blob: 12abc256a20ecb89d9d604e4ae19de7a7effcc5d [file] [log] [blame]
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001/*
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 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080016
Adam Lesinskibebfcc42018-02-12 14:27:46 -080017#define ATRACE_TAG ATRACE_TAG_RESOURCES
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#define LOG_TAG "asset"
19
Dan Albert46d84442014-11-18 16:07:51 -080020#include <inttypes.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <stdio.h>
Adam Lesinskibde1df22018-02-09 11:12:22 -080022#include <sys/stat.h>
Adam Lesinskibebfcc42018-02-12 14:27:46 -080023#include <sys/types.h>
24#include <sys/wait.h>
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020025#include <unistd.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010026
Dan Albert46d84442014-11-18 16:07:51 -080027#include <private/android_filesystem_config.h> // for AID_SYSTEM
28
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020029#include <sstream>
30#include <string>
31
Adam Lesinskibebfcc42018-02-12 14:27:46 -080032#include "android-base/logging.h"
33#include "android-base/properties.h"
34#include "android-base/stringprintf.h"
35#include "android_runtime/android_util_AssetManager.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080036#include "android_runtime/AndroidRuntime.h"
37#include "android_util_Binder.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080038#include "androidfw/Asset.h"
39#include "androidfw/AssetManager.h"
40#include "androidfw/AssetManager2.h"
41#include "androidfw/AttributeResolution.h"
42#include "androidfw/MutexGuard.h"
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020043#include "androidfw/PosixUtils.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080044#include "androidfw/ResourceTypes.h"
Winson2f3669b2019-01-11 11:28:34 -080045#include "androidfw/ResourceUtils.h"
46
Dan Albert3a091b72014-11-20 15:41:25 -080047#include "core_jni_helpers.h"
48#include "jni.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080049#include "nativehelper/JNIHelp.h"
50#include "nativehelper/ScopedPrimitiveArray.h"
51#include "nativehelper/ScopedStringChars.h"
52#include "nativehelper/ScopedUtfChars.h"
Dan Albert46d84442014-11-18 16:07:51 -080053#include "utils/Log.h"
Adam Lesinski11875902017-01-23 12:58:11 -080054#include "utils/misc.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080055#include "utils/String8.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080056#include "utils/Trace.h"
Dan Albert46d84442014-11-18 16:07:51 -080057
Mårten Kongstad48d22322014-01-31 14:43:27 +010058extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
59extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
60
Adam Lesinskibebfcc42018-02-12 14:27:46 -080061using ::android::base::StringPrintf;
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020062using ::android::util::ExecuteBinary;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64namespace android {
65
66// ----------------------------------------------------------------------------
67
Adam Lesinskibebfcc42018-02-12 14:27:46 -080068static 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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076} gTypedValueOffsets;
77
Nicolas Geoffraya55a59a2018-05-10 15:00:13 +010078// This is also used by asset_manager.cpp.
79assetmanager_offsets_t gAssetManagerOffsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
Adam Lesinskibebfcc42018-02-12 14:27:46 -080081static struct {
82 jfieldID native_ptr;
83} gApkAssetsFields;
84
85static struct sparsearray_offsets_t {
86 jclass classObject;
87 jmethodID constructor;
88 jmethodID put;
Adam Lesinskide898ff2014-01-29 18:20:45 -080089} gSparseArrayOffsets;
90
Adam Lesinskibebfcc42018-02-12 14:27:46 -080091static struct configuration_offsets_t {
92 jclass classObject;
93 jmethodID constructor;
94 jfieldID mSmallestScreenWidthDpOffset;
95 jfieldID mScreenWidthDpOffset;
96 jfieldID mScreenHeightDpOffset;
Filip Gruszczynski23493322015-07-29 17:02:59 -070097} gConfigurationOffsets;
98
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +010099static struct arraymap_offsets_t {
100 jclass classObject;
101 jmethodID constructor;
102 jmethodID put;
103} gArrayMapOffsets;
104
Wei Wangd41a9612019-10-10 11:34:13 -0700105static jclass g_stringClass = nullptr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
107// ----------------------------------------------------------------------------
108
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800109// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
110constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
111 return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
112}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800114constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
115 return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200118static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
119 jclass /*clazz*/) {
120 // --input-directory can be given multiple times, but idmap2 expects the directory to exist
121 std::vector<std::string> input_dirs;
122 struct stat st;
123 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
124 input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
125 }
126
127 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
128 input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
129 }
130
Jeongik Chacba95792019-07-09 23:58:01 +0900131 if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
132 input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR);
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200133 }
134
Mårten Kongstad48c24cf2019-02-25 10:54:09 +0100135 if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
136 input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR);
137 }
138
Mårten Kongstadeb8a5c02019-02-25 14:18:17 +0100139 if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) {
140 input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR);
141 }
142
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200143 if (input_dirs.empty()) {
144 LOG(WARNING) << "no directories for idmap2 to scan";
145 return env->NewObjectArray(0, g_stringClass, nullptr);
146 }
147
Yabin Cuia60dc9e2019-02-26 16:12:46 -0800148 if (access("/system/bin/idmap2", X_OK) == -1) {
149 PLOG(WARNING) << "unable to execute idmap2";
150 return nullptr;
151 }
152
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200153 std::vector<std::string> argv{"/system/bin/idmap2",
154 "scan",
155 "--recursive",
156 "--target-package-name", "android",
157 "--target-apk-path", "/system/framework/framework-res.apk",
158 "--output-directory", "/data/resource-cache"};
159
160 for (const auto& dir : input_dirs) {
161 argv.push_back("--input-directory");
162 argv.push_back(dir);
163 }
164
165 const auto result = ExecuteBinary(argv);
166
167 if (!result) {
168 LOG(ERROR) << "failed to execute idmap2";
169 return nullptr;
170 }
171
172 if (result->status != 0) {
173 LOG(ERROR) << "idmap2: " << result->stderr;
174 return nullptr;
175 }
176
177 std::vector<std::string> idmap_paths;
178 std::istringstream input(result->stdout);
179 std::string path;
180 while (std::getline(input, path)) {
181 idmap_paths.push_back(path);
182 }
183
184 jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
185 if (array == nullptr) {
186 return nullptr;
187 }
188 for (size_t i = 0; i < idmap_paths.size(); i++) {
189 const std::string path = idmap_paths[i];
190 jstring java_string = env->NewStringUTF(path.c_str());
191 if (env->ExceptionCheck()) {
192 return nullptr;
193 }
194 env->SetObjectArrayElement(array, i, java_string);
195 env->DeleteLocalRef(java_string);
196 }
197 return array;
198}
199
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800200static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
201 uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
202 env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
203 env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
204 ApkAssetsCookieToJavaCookie(cookie));
205 env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
206 env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
207 env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
208 env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
209 if (config != nullptr) {
210 env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
211 }
212 return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
Adam Lesinski11875902017-01-23 12:58:11 -0800213}
214
215// ----------------------------------------------------------------------------
216
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800217// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
218struct GuardedAssetManager : public ::AAssetManager {
219 Guarded<AssetManager2> guarded_assetmanager;
Adam Lesinski11875902017-01-23 12:58:11 -0800220};
221
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800222::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
223 jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
224 ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
225 if (am == nullptr) {
226 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
227 return nullptr;
228 }
229 return am;
230}
Adam Lesinski11875902017-01-23 12:58:11 -0800231
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800232Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
233 if (assetmanager == nullptr) {
234 return nullptr;
235 }
236 return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
237}
Adam Lesinski11875902017-01-23 12:58:11 -0800238
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800239Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
240 return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
241}
Adam Lesinski11875902017-01-23 12:58:11 -0800242
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800243static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
244 return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
245}
Adam Lesinski11875902017-01-23 12:58:11 -0800246
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100247static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
Ryan Mitchell2e394222019-08-28 12:10:51 -0700248 jstring package_name) {
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100249 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
250 const ScopedUtfChars package_name_utf8(env, package_name);
251 CHECK(package_name_utf8.c_str() != nullptr);
252 const std::string std_package_name(package_name_utf8.c_str());
253 const std::unordered_map<std::string, std::string>* map = nullptr;
254
255 assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
256 if (this_package_name == std_package_name) {
257 map = assetmanager->GetOverlayableMapForPackage(package_id);
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800258 return false;
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100259 }
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800260 return true;
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100261 });
262
263 if (map == nullptr) {
264 return nullptr;
265 }
266
267 jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor);
268 if (array_map == nullptr) {
269 return nullptr;
270 }
271
272 for (const auto& iter : *map) {
273 jstring name = env->NewStringUTF(iter.first.c_str());
274 if (env->ExceptionCheck()) {
275 return nullptr;
276 }
277
278 jstring actor = env->NewStringUTF(iter.second.c_str());
279 if (env->ExceptionCheck()) {
280 env->DeleteLocalRef(name);
281 return nullptr;
282 }
283
284 env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor);
285
286 env->DeleteLocalRef(name);
287 env->DeleteLocalRef(actor);
288 }
289
290 return array_map;
291}
292
Ryan Mitchell2e394222019-08-28 12:10:51 -0700293static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr,
294 jstring package_name) {
295 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
296 const ScopedUtfChars package_name_utf8(env, package_name);
297 CHECK(package_name_utf8.c_str() != nullptr);
298 const std::string std_package_name(package_name_utf8.c_str());
299
300 std::string result;
301 if (!assetmanager->GetOverlayablesToString(std_package_name, &result)) {
302 return nullptr;
303 }
304
305 return env->NewStringUTF(result.c_str());
306}
307
Brett Chabot15c7bcd2019-06-19 10:19:00 -0700308#ifdef __ANDROID__ // Layoutlib does not support parcel
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800309static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
310 jlongArray out_offsets) {
311 off64_t start_offset, length;
312 int fd = asset->openFileDescriptor(&start_offset, &length);
313 asset.reset();
Adam Lesinski11875902017-01-23 12:58:11 -0800314
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800315 if (fd < 0) {
316 jniThrowException(env, "java/io/FileNotFoundException",
317 "This file can not be opened as a file descriptor; it is probably "
318 "compressed");
319 return nullptr;
320 }
Adam Lesinski11875902017-01-23 12:58:11 -0800321
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800322 jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
323 if (offsets == nullptr) {
324 close(fd);
325 return nullptr;
326 }
327
328 offsets[0] = start_offset;
329 offsets[1] = length;
330
331 env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
332
333 jobject file_desc = jniCreateFileDescriptor(env, fd);
334 if (file_desc == nullptr) {
335 close(fd);
336 return nullptr;
337 }
338 return newParcelFileDescriptor(env, file_desc);
339}
Brett Chabot15c7bcd2019-06-19 10:19:00 -0700340#else
341static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
342 jlongArray out_offsets) {
343 jniThrowException(env, "java/lang/UnsupportedOperationException",
344 "Implement me");
345 // never reached
346 return nullptr;
347}
348#endif
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800349
350static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
351 return Asset::getGlobalCount();
352}
353
354static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
355 String8 alloc = Asset::getAssetAllocations();
356 if (alloc.length() <= 0) {
357 return nullptr;
358 }
359 return env->NewStringUTF(alloc.string());
360}
361
362static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
363 // TODO(adamlesinski): Switch to AssetManager2.
364 return AssetManager::getGlobalCount();
365}
366
367static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
368 // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
369 // AssetManager2 in a contiguous block (GuardedAssetManager).
370 return reinterpret_cast<jlong>(new GuardedAssetManager());
371}
372
373static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
374 delete reinterpret_cast<GuardedAssetManager*>(ptr);
375}
376
377static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
378 jobjectArray apk_assets_array, jboolean invalidate_caches) {
379 ATRACE_NAME("AssetManager::SetApkAssets");
380
381 const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
382 std::vector<const ApkAssets*> apk_assets;
383 apk_assets.reserve(apk_assets_len);
384 for (jsize i = 0; i < apk_assets_len; i++) {
385 jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
386 if (obj == nullptr) {
387 std::string msg = StringPrintf("ApkAssets at index %d is null", i);
388 jniThrowNullPointerException(env, msg.c_str());
389 return;
390 }
391
392 jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
393 if (env->ExceptionCheck()) {
394 return;
395 }
396 apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
397 }
398
399 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
400 assetmanager->SetApkAssets(apk_assets, invalidate_caches);
401}
402
403static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
404 jstring locale, jint orientation, jint touchscreen, jint density,
405 jint keyboard, jint keyboard_hidden, jint navigation,
406 jint screen_width, jint screen_height,
407 jint smallest_screen_width_dp, jint screen_width_dp,
408 jint screen_height_dp, jint screen_layout, jint ui_mode,
409 jint color_mode, jint major_version) {
410 ATRACE_NAME("AssetManager::SetConfiguration");
411
412 ResTable_config configuration;
413 memset(&configuration, 0, sizeof(configuration));
414 configuration.mcc = static_cast<uint16_t>(mcc);
415 configuration.mnc = static_cast<uint16_t>(mnc);
416 configuration.orientation = static_cast<uint8_t>(orientation);
417 configuration.touchscreen = static_cast<uint8_t>(touchscreen);
418 configuration.density = static_cast<uint16_t>(density);
419 configuration.keyboard = static_cast<uint8_t>(keyboard);
420 configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
421 configuration.navigation = static_cast<uint8_t>(navigation);
422 configuration.screenWidth = static_cast<uint16_t>(screen_width);
423 configuration.screenHeight = static_cast<uint16_t>(screen_height);
424 configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
425 configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
426 configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
427 configuration.screenLayout = static_cast<uint8_t>(screen_layout);
428 configuration.uiMode = static_cast<uint8_t>(ui_mode);
429 configuration.colorMode = static_cast<uint8_t>(color_mode);
430 configuration.sdkVersion = static_cast<uint16_t>(major_version);
431
432 if (locale != nullptr) {
433 ScopedUtfChars locale_utf8(env, locale);
434 CHECK(locale_utf8.c_str() != nullptr);
435 configuration.setBcp47Locale(locale_utf8.c_str());
436 }
437
438 // Constants duplicated from Java class android.content.res.Configuration.
439 static const jint kScreenLayoutRoundMask = 0x300;
440 static const jint kScreenLayoutRoundShift = 8;
441
442 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
443 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
444 // into screenLayout2.
445 configuration.screenLayout2 =
446 static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
447
448 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
449 assetmanager->SetConfiguration(configuration);
450}
451
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800452static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
453 jboolean includeOverlays,
454 jboolean includeLoaders) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800455 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
456
457 jobject sparse_array =
458 env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
459
460 if (sparse_array == nullptr) {
461 // An exception is pending.
462 return nullptr;
463 }
464
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800465 // Optionally exclude overlays and loaders.
466 uint64_t exclusion_flags = ((includeOverlays) ? 0U : PROPERTY_OVERLAY)
467 | ((includeLoaders) ? 0U : PROPERTY_LOADER);
468
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800469 assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800470 jstring jpackage_name = env->NewStringUTF(package_name.c_str());
471 if (jpackage_name == nullptr) {
472 // An exception is pending.
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800473 return false;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800474 }
475
476 env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
477 jpackage_name);
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800478 return true;
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800479 }, exclusion_flags);
480
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800481 return sparse_array;
482}
483
Ryan Mitchell192400c2020-04-02 09:54:23 -0700484static jboolean ContainsAllocatedTable(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
485 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
486 return assetmanager->ContainsAllocatedTable();
487}
488
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800489static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
490 ScopedUtfChars path_utf8(env, path);
491 if (path_utf8.c_str() == nullptr) {
492 // This will throw NPE.
493 return nullptr;
494 }
495
496 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
497 std::unique_ptr<AssetDir> asset_dir =
498 assetmanager->OpenDir(path_utf8.c_str());
499 if (asset_dir == nullptr) {
500 jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
501 return nullptr;
502 }
503
504 const size_t file_count = asset_dir->getFileCount();
505
506 jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
507 if (array == nullptr) {
508 return nullptr;
509 }
510
511 for (size_t i = 0; i < file_count; i++) {
512 jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
513
514 // Check for errors creating the strings (if malformed or no memory).
515 if (env->ExceptionCheck()) {
516 return nullptr;
517 }
518
519 env->SetObjectArrayElement(array, i, java_string);
520
521 // If we have a large amount of string in our array, we might overflow the
522 // local reference table of the VM.
523 env->DeleteLocalRef(java_string);
524 }
525 return array;
526}
527
528static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
529 jint access_mode) {
530 ScopedUtfChars asset_path_utf8(env, asset_path);
531 if (asset_path_utf8.c_str() == nullptr) {
532 // This will throw NPE.
533 return 0;
534 }
535
536 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
537
538 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
539 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
540 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
541 return 0;
542 }
543
544 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
545 std::unique_ptr<Asset> asset =
546 assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
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
554static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
555 jlongArray out_offsets) {
556 ScopedUtfChars asset_path_utf8(env, asset_path);
557 if (asset_path_utf8.c_str() == nullptr) {
558 // This will throw NPE.
559 return nullptr;
560 }
561
562 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
563
564 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
565 std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
566 if (!asset) {
567 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
568 return nullptr;
569 }
570 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
571}
572
573static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
574 jstring asset_path, jint access_mode) {
575 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
576 ScopedUtfChars asset_path_utf8(env, asset_path);
577 if (asset_path_utf8.c_str() == nullptr) {
578 // This will throw NPE.
579 return 0;
580 }
581
582 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
583
584 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
585 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
586 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
587 return 0;
588 }
589
590 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
591 std::unique_ptr<Asset> asset;
592 if (cookie != kInvalidCookie) {
593 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
594 static_cast<Asset::AccessMode>(access_mode));
595 } else {
596 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
597 static_cast<Asset::AccessMode>(access_mode));
598 }
599
600 if (!asset) {
601 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
602 return 0;
603 }
604 return reinterpret_cast<jlong>(asset.release());
605}
606
607static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
608 jstring asset_path, jlongArray out_offsets) {
609 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
610 ScopedUtfChars asset_path_utf8(env, asset_path);
611 if (asset_path_utf8.c_str() == nullptr) {
612 // This will throw NPE.
613 return nullptr;
614 }
615
616 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
617
618 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
619 std::unique_ptr<Asset> asset;
620 if (cookie != kInvalidCookie) {
621 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
622 } else {
623 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
624 }
625
626 if (!asset) {
627 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
628 return nullptr;
629 }
630 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
631}
632
633static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
634 jstring asset_path) {
635 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
636 ScopedUtfChars asset_path_utf8(env, asset_path);
637 if (asset_path_utf8.c_str() == nullptr) {
638 // This will throw NPE.
639 return 0;
640 }
641
642 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
643
644 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
645 std::unique_ptr<Asset> asset;
646 if (cookie != kInvalidCookie) {
647 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
648 } else {
649 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
650 }
651
652 if (!asset) {
653 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
654 return 0;
655 }
656
657 // May be nullptr.
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700658 std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
659 assetmanager->GetDynamicRefTableForCookie(cookie);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800660
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700661 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
662 std::move(dynamic_ref_table));
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800663 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
664 asset.reset();
665
666 if (err != NO_ERROR) {
667 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
668 return 0;
669 }
670 return reinterpret_cast<jlong>(xml_tree.release());
671}
672
Winson9947f1e2019-08-16 10:20:39 -0700673static jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int jcookie,
674 jobject file_descriptor) {
675 int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
676 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAssetFd(%d)", fd).c_str());
677 if (fd < 0) {
678 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
679 return 0;
680 }
681
682 base::unique_fd dup_fd(::fcntl(fd, F_DUPFD_CLOEXEC, 0));
683 if (dup_fd < 0) {
684 jniThrowIOException(env, errno);
685 return 0;
686 }
687
688 std::unique_ptr<Asset>
689 asset(Asset::createFromFd(dup_fd.release(), nullptr, Asset::AccessMode::ACCESS_BUFFER));
690
691 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
692 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
693
694 // May be nullptr.
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700695 std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
696 assetmanager->GetDynamicRefTableForCookie(cookie);
Winson9947f1e2019-08-16 10:20:39 -0700697
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700698 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
699 std::move(dynamic_ref_table));
Winson9947f1e2019-08-16 10:20:39 -0700700 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
701 asset.reset();
702
703 if (err != NO_ERROR) {
704 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
705 return 0;
706 }
707 return reinterpret_cast<jlong>(xml_tree.release());
708}
709
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800710static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
711 jshort density, jobject typed_value,
712 jboolean resolve_references) {
713 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
714 Res_value value;
715 ResTable_config selected_config;
716 uint32_t flags;
717 ApkAssetsCookie cookie =
718 assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
719 static_cast<uint16_t>(density), &value, &selected_config, &flags);
720 if (cookie == kInvalidCookie) {
721 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
722 }
723
724 uint32_t ref = static_cast<uint32_t>(resid);
725 if (resolve_references) {
726 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
727 if (cookie == kInvalidCookie) {
728 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
729 }
730 }
731 return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
732}
733
734static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
735 jint bag_entry_id, jobject typed_value) {
736 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
737 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
738 if (bag == nullptr) {
739 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
740 }
741
742 uint32_t type_spec_flags = bag->type_spec_flags;
743 ApkAssetsCookie cookie = kInvalidCookie;
744 const Res_value* bag_value = nullptr;
745 for (const ResolvedBag::Entry& entry : bag) {
746 if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
747 cookie = entry.cookie;
748 bag_value = &entry.value;
749
750 // Keep searching (the old implementation did that).
751 }
752 }
753
754 if (cookie == kInvalidCookie) {
755 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
756 }
757
758 Res_value value = *bag_value;
759 uint32_t ref = static_cast<uint32_t>(resid);
760 ResTable_config selected_config;
761 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
762 if (cookie == kInvalidCookie) {
763 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
764 }
765 return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
766}
767
768static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
769 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
770 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
771 if (bag == nullptr) {
772 return nullptr;
773 }
774
775 jintArray array = env->NewIntArray(bag->entry_count);
776 if (env->ExceptionCheck()) {
777 return nullptr;
778 }
779
780 for (uint32_t i = 0; i < bag->entry_count; i++) {
781 jint attr_resid = bag->entries[i].key;
782 env->SetIntArrayRegion(array, i, 1, &attr_resid);
783 }
784 return array;
785}
786
787static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
788 jint resid) {
789 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
790 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
791 if (bag == nullptr) {
792 return nullptr;
793 }
794
795 jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
796 if (array == nullptr) {
797 return nullptr;
798 }
799
800 for (uint32_t i = 0; i < bag->entry_count; i++) {
801 const ResolvedBag::Entry& entry = bag->entries[i];
802
803 // Resolve any references to their final value.
804 Res_value value = entry.value;
805 ResTable_config selected_config;
806 uint32_t flags;
807 uint32_t ref;
808 ApkAssetsCookie cookie =
809 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
810 if (cookie == kInvalidCookie) {
811 return nullptr;
812 }
813
814 if (value.dataType == Res_value::TYPE_STRING) {
815 const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
816 const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
817
818 jstring java_string = nullptr;
819 size_t str_len;
820 const char* str_utf8 = pool->string8At(value.data, &str_len);
821 if (str_utf8 != nullptr) {
822 java_string = env->NewStringUTF(str_utf8);
823 } else {
824 const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
825 java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
826 }
827
828 // Check for errors creating the strings (if malformed or no memory).
829 if (env->ExceptionCheck()) {
830 return nullptr;
831 }
832
833 env->SetObjectArrayElement(array, i, java_string);
834
835 // If we have a large amount of string in our array, we might overflow the
836 // local reference table of the VM.
837 env->DeleteLocalRef(java_string);
838 }
839 }
840 return array;
841}
842
843static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
844 jint resid) {
845 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
846 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
847 if (bag == nullptr) {
848 return nullptr;
849 }
850
851 jintArray array = env->NewIntArray(bag->entry_count * 2);
852 if (array == nullptr) {
853 return nullptr;
854 }
855
856 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
857 if (buffer == nullptr) {
858 return nullptr;
859 }
860
861 for (size_t i = 0; i < bag->entry_count; i++) {
862 const ResolvedBag::Entry& entry = bag->entries[i];
863 Res_value value = entry.value;
864 ResTable_config selected_config;
865 uint32_t flags;
866 uint32_t ref;
867 ApkAssetsCookie cookie =
868 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
869 if (cookie == kInvalidCookie) {
870 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
871 return nullptr;
872 }
873
874 jint string_index = -1;
875 if (value.dataType == Res_value::TYPE_STRING) {
876 string_index = static_cast<jint>(value.data);
877 }
878
879 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
880 buffer[(i * 2) + 1] = string_index;
881 }
882 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
883 return array;
884}
885
886static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
887 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
888 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
889 if (bag == nullptr) {
890 return nullptr;
891 }
892
893 jintArray array = env->NewIntArray(bag->entry_count);
894 if (array == nullptr) {
895 return nullptr;
896 }
897
898 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
899 if (buffer == nullptr) {
900 return nullptr;
901 }
902
903 for (size_t i = 0; i < bag->entry_count; i++) {
904 const ResolvedBag::Entry& entry = bag->entries[i];
905 Res_value value = entry.value;
906 ResTable_config selected_config;
907 uint32_t flags;
908 uint32_t ref;
909 ApkAssetsCookie cookie =
910 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
911 if (cookie == kInvalidCookie) {
912 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
913 return nullptr;
914 }
915
916 if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
917 buffer[i] = static_cast<jint>(value.data);
918 }
919 }
920 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
921 return array;
922}
923
924static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
925 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
926 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
927 if (bag == nullptr) {
928 return -1;
929 }
930 return static_cast<jint>(bag->entry_count);
931}
932
933static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
934 jintArray out_data) {
935 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
936 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
937 if (bag == nullptr) {
938 return -1;
939 }
940
941 const jsize out_data_length = env->GetArrayLength(out_data);
942 if (env->ExceptionCheck()) {
943 return -1;
944 }
945
946 if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
947 jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
948 return -1;
949 }
950
951 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
952 if (buffer == nullptr) {
953 return -1;
954 }
955
956 jint* cursor = buffer;
957 for (size_t i = 0; i < bag->entry_count; i++) {
958 const ResolvedBag::Entry& entry = bag->entries[i];
959 Res_value value = entry.value;
960 ResTable_config selected_config;
961 selected_config.density = 0;
962 uint32_t flags = bag->type_spec_flags;
Todd Kennedy1d63cc32018-04-18 10:25:45 -0700963 uint32_t ref = 0;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800964 ApkAssetsCookie cookie =
965 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
966 if (cookie == kInvalidCookie) {
967 env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
968 return -1;
969 }
970
971 // Deal with the special @null value -- it turns back to TYPE_NULL.
972 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
973 value.dataType = Res_value::TYPE_NULL;
974 value.data = Res_value::DATA_NULL_UNDEFINED;
975 }
976
977 cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
978 cursor[STYLE_DATA] = static_cast<jint>(value.data);
979 cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
980 cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
981 cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
982 cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
983 cursor += STYLE_NUM_ENTRIES;
984 }
985 env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
986 return static_cast<jint>(bag->entry_count);
987}
988
989static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
990 jstring def_type, jstring def_package) {
991 ScopedUtfChars name_utf8(env, name);
992 if (name_utf8.c_str() == nullptr) {
993 // This will throw NPE.
994 return 0;
995 }
996
997 std::string type;
998 if (def_type != nullptr) {
999 ScopedUtfChars type_utf8(env, def_type);
1000 CHECK(type_utf8.c_str() != nullptr);
1001 type = type_utf8.c_str();
1002 }
1003
1004 std::string package;
1005 if (def_package != nullptr) {
1006 ScopedUtfChars package_utf8(env, def_package);
1007 CHECK(package_utf8.c_str() != nullptr);
1008 package = package_utf8.c_str();
1009 }
1010 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1011 return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
1012}
1013
1014static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1015 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1016 AssetManager2::ResourceName name;
1017 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1018 return nullptr;
1019 }
1020
Winson2f3669b2019-01-11 11:28:34 -08001021 std::string result = ToFormattedResourceString(&name);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001022 return env->NewStringUTF(result.c_str());
1023}
1024
1025static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1026 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1027 AssetManager2::ResourceName name;
1028 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1029 return nullptr;
1030 }
1031
1032 if (name.package != nullptr) {
1033 return env->NewStringUTF(name.package);
1034 }
1035 return nullptr;
1036}
1037
1038static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1039 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1040 AssetManager2::ResourceName name;
1041 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1042 return nullptr;
1043 }
1044
1045 if (name.type != nullptr) {
1046 return env->NewStringUTF(name.type);
1047 } else if (name.type16 != nullptr) {
1048 return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
1049 }
1050 return nullptr;
1051}
1052
1053static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1054 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1055 AssetManager2::ResourceName name;
1056 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1057 return nullptr;
1058 }
1059
1060 if (name.entry != nullptr) {
1061 return env->NewStringUTF(name.entry);
1062 } else if (name.entry16 != nullptr) {
1063 return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
1064 }
1065 return nullptr;
1066}
1067
Winson2f3669b2019-01-11 11:28:34 -08001068static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
1069 jclass /*clazz*/,
1070 jlong ptr,
1071 jboolean enabled) {
1072 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1073 assetmanager->SetResourceResolutionLoggingEnabled(enabled);
1074}
1075
1076static jstring NativeGetLastResourceResolution(JNIEnv* env,
1077 jclass /*clazz*/,
1078 jlong ptr) {
1079 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1080 std::string resolution = assetmanager->GetLastResourceResolution();
1081 if (resolution.empty()) {
1082 return nullptr;
1083 } else {
1084 return env->NewStringUTF(resolution.c_str());
1085 }
1086}
1087
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001088static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
1089 jboolean exclude_system) {
1090 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1091 std::set<std::string> locales =
1092 assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
1093
1094 jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
1095 if (array == nullptr) {
1096 return nullptr;
1097 }
1098
1099 size_t idx = 0;
1100 for (const std::string& locale : locales) {
1101 jstring java_string = env->NewStringUTF(locale.c_str());
1102 if (java_string == nullptr) {
1103 return nullptr;
1104 }
1105 env->SetObjectArrayElement(array, idx++, java_string);
1106 env->DeleteLocalRef(java_string);
1107 }
1108 return array;
1109}
1110
1111static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
1112 jobject result =
1113 env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1114 if (result == nullptr) {
1115 return nullptr;
1116 }
1117
1118 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1119 config.smallestScreenWidthDp);
1120 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1121 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1122 return result;
1123}
1124
1125static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1126 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1127 std::set<ResTable_config> configurations =
1128 assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1129
1130 jobjectArray array =
1131 env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1132 if (array == nullptr) {
1133 return nullptr;
1134 }
1135
1136 size_t idx = 0;
1137 for (const ResTable_config& configuration : configurations) {
1138 jobject java_configuration = ConstructConfigurationObject(env, configuration);
1139 if (java_configuration == nullptr) {
1140 return nullptr;
1141 }
1142
1143 env->SetObjectArrayElement(array, idx++, java_configuration);
1144 env->DeleteLocalRef(java_configuration);
1145 }
1146 return array;
1147}
1148
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001149static jintArray NativeAttributeResolutionStack(
1150 JNIEnv* env, jclass /*clazz*/, jlong ptr,
1151 jlong theme_ptr, jint xml_style_res,
1152 jint def_style_attr, jint def_style_resid) {
1153
1154 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1155 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1156 CHECK(theme->GetAssetManager() == &(*assetmanager));
1157 (void) assetmanager;
1158
1159 // Load default style from attribute, if specified...
1160 uint32_t def_style_flags = 0u;
1161 if (def_style_attr != 0) {
1162 Res_value value;
1163 if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
1164 if (value.dataType == Res_value::TYPE_REFERENCE) {
1165 def_style_resid = value.data;
1166 }
1167 }
1168 }
1169
1170 auto style_stack = assetmanager->GetBagResIdStack(xml_style_res);
1171 auto def_style_stack = assetmanager->GetBagResIdStack(def_style_resid);
1172
1173 jintArray array = env->NewIntArray(style_stack.size() + def_style_stack.size());
1174 if (env->ExceptionCheck()) {
1175 return nullptr;
1176 }
1177
1178 for (uint32_t i = 0; i < style_stack.size(); i++) {
1179 jint attr_resid = style_stack[i];
1180 env->SetIntArrayRegion(array, i, 1, &attr_resid);
1181 }
1182 for (uint32_t i = 0; i < def_style_stack.size(); i++) {
1183 jint attr_resid = def_style_stack[i];
1184 env->SetIntArrayRegion(array, style_stack.size() + i, 1, &attr_resid);
1185 }
1186 return array;
1187}
1188
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001189static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1190 jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1191 jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
1192 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1193 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1194 CHECK(theme->GetAssetManager() == &(*assetmanager));
1195 (void) assetmanager;
1196
1197 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1198 uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
1199 uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
1200
1201 jsize attrs_len = env->GetArrayLength(java_attrs);
1202 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1203 if (attrs == nullptr) {
1204 return;
1205 }
1206
1207 ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
1208 static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
1209 out_values, out_indices);
1210 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1211}
1212
1213static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1214 jint def_style_attr, jint def_style_resid, jintArray java_values,
1215 jintArray java_attrs, jintArray out_java_values,
1216 jintArray out_java_indices) {
1217 const jsize attrs_len = env->GetArrayLength(java_attrs);
1218 const jsize out_values_len = env->GetArrayLength(out_java_values);
1219 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1220 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1221 return JNI_FALSE;
1222 }
1223
1224 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1225 if (attrs == nullptr) {
1226 return JNI_FALSE;
1227 }
1228
1229 jint* values = nullptr;
1230 jsize values_len = 0;
1231 if (java_values != nullptr) {
1232 values_len = env->GetArrayLength(java_values);
1233 values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
1234 if (values == nullptr) {
1235 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1236 return JNI_FALSE;
1237 }
1238 }
1239
1240 jint* out_values =
1241 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1242 if (out_values == nullptr) {
1243 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1244 if (values != nullptr) {
1245 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1246 }
1247 return JNI_FALSE;
1248 }
1249
1250 jint* out_indices = nullptr;
1251 if (out_java_indices != nullptr) {
1252 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1253 if (out_indices_len > attrs_len) {
1254 out_indices =
1255 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1256 if (out_indices == nullptr) {
1257 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1258 if (values != nullptr) {
1259 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1260 }
1261 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1262 return JNI_FALSE;
1263 }
1264 }
1265 }
1266
1267 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1268 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1269 CHECK(theme->GetAssetManager() == &(*assetmanager));
1270 (void) assetmanager;
1271
1272 bool result = ResolveAttrs(
1273 theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1274 reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1275 attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1276 if (out_indices != nullptr) {
1277 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1278 }
1279
1280 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1281 if (values != nullptr) {
1282 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1283 }
1284 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1285 return result ? JNI_TRUE : JNI_FALSE;
1286}
1287
1288static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1289 jlong xml_parser_ptr, jintArray java_attrs,
1290 jintArray out_java_values, jintArray out_java_indices) {
1291 const jsize attrs_len = env->GetArrayLength(java_attrs);
1292 const jsize out_values_len = env->GetArrayLength(out_java_values);
1293 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1294 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1295 return JNI_FALSE;
1296 }
1297
1298 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1299 if (attrs == nullptr) {
1300 return JNI_FALSE;
1301 }
1302
1303 jint* out_values =
1304 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1305 if (out_values == nullptr) {
1306 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1307 return JNI_FALSE;
1308 }
1309
1310 jint* out_indices = nullptr;
1311 if (out_java_indices != nullptr) {
1312 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1313 if (out_indices_len > attrs_len) {
1314 out_indices =
1315 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1316 if (out_indices == nullptr) {
1317 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1318 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1319 return JNI_FALSE;
1320 }
1321 }
1322 }
1323
1324 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1325 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1326
1327 bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1328 reinterpret_cast<uint32_t*>(attrs), attrs_len,
1329 reinterpret_cast<uint32_t*>(out_values),
1330 reinterpret_cast<uint32_t*>(out_indices));
1331
1332 if (out_indices != nullptr) {
1333 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1334 }
1335 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1336 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1337 return result ? JNI_TRUE : JNI_FALSE;
1338}
1339
1340static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1341 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1342 return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1343}
1344
1345static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1346 delete reinterpret_cast<Theme*>(theme_ptr);
1347}
1348
1349static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1350 jint resid, jboolean force) {
1351 // AssetManager is accessed via the theme, so grab an explicit lock here.
1352 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1353 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1354 CHECK(theme->GetAssetManager() == &(*assetmanager));
1355 (void) assetmanager;
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
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001364static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1365 jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001366 Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1367 Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001368
1369 if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1370 ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
1371 CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
1372 (void) dst_assetmanager;
1373
1374 ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
1375 CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
1376 (void) src_assetmanager;
1377
1378 dst_theme->SetTo(*src_theme);
1379 } else {
1380 dst_theme->SetTo(*src_theme);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001381 }
1382}
1383
1384static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1385 reinterpret_cast<Theme*>(theme_ptr)->Clear();
1386}
1387
1388static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1389 jint resid, jobject typed_value,
1390 jboolean resolve_references) {
1391 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1392 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1393 CHECK(theme->GetAssetManager() == &(*assetmanager));
1394 (void) assetmanager;
1395
1396 Res_value value;
1397 uint32_t flags;
1398 ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1399 if (cookie == kInvalidCookie) {
1400 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1401 }
1402
1403 uint32_t ref = 0u;
1404 if (resolve_references) {
1405 ResTable_config selected_config;
1406 cookie =
1407 theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1408 if (cookie == kInvalidCookie) {
1409 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1410 }
1411 }
1412 return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1413}
1414
1415static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1416 jint priority, jstring tag, jstring prefix) {
1417 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1418 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1419 CHECK(theme->GetAssetManager() == &(*assetmanager));
1420 (void) assetmanager;
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001421 (void) priority;
1422 (void) tag;
1423 (void) prefix;
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001424
1425 theme->Dump();
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001426}
1427
1428static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1429 jlong theme_ptr) {
1430 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1431 return static_cast<jint>(theme->GetChangingConfigurations());
1432}
1433
1434static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1435 delete reinterpret_cast<Asset*>(asset_ptr);
1436}
1437
1438static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1439 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1440 uint8_t b;
1441 ssize_t res = asset->read(&b, sizeof(b));
1442 return res == sizeof(b) ? static_cast<jint>(b) : -1;
1443}
1444
1445static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1446 jint offset, jint len) {
1447 if (len == 0) {
1448 return 0;
1449 }
1450
1451 jsize buffer_len = env->GetArrayLength(java_buffer);
1452 if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1453 offset > buffer_len - len) {
1454 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1455 return -1;
1456 }
1457
1458 ScopedByteArrayRW byte_array(env, java_buffer);
1459 if (byte_array.get() == nullptr) {
1460 return -1;
1461 }
1462
1463 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1464 ssize_t res = asset->read(byte_array.get() + offset, len);
1465 if (res < 0) {
1466 jniThrowException(env, "java/io/IOException", "");
1467 return -1;
1468 }
1469 return res > 0 ? static_cast<jint>(res) : -1;
1470}
1471
1472static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1473 jint whence) {
1474 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1475 return static_cast<jlong>(asset->seek(
1476 static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1477}
1478
1479static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1480 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1481 return static_cast<jlong>(asset->getLength());
1482}
1483
1484static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1485 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1486 return static_cast<jlong>(asset->getRemainingLength());
1487}
1488
1489// ----------------------------------------------------------------------------
1490
1491// JNI registration.
1492static const JNINativeMethod gAssetManagerMethods[] = {
1493 // AssetManager setup methods.
1494 {"nativeCreate", "()J", (void*)NativeCreate},
1495 {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1496 {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1497 {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1498 (void*)NativeSetConfiguration},
Ryan Mitchell73bfe412019-11-12 16:22:04 -08001499 {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001500 (void*)NativeGetAssignedPackageIdentifiers},
1501
1502 // AssetManager file methods.
Ryan Mitchell192400c2020-04-02 09:54:23 -07001503 {"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001504 {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1505 {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1506 {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1507 (void*)NativeOpenAssetFd},
1508 {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1509 {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1510 (void*)NativeOpenNonAssetFd},
1511 {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
Winson9947f1e2019-08-16 10:20:39 -07001512 {"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001513
1514 // AssetManager resource methods.
1515 {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1516 {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1517 (void*)NativeGetResourceBagValue},
1518 {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1519 {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1520 (void*)NativeGetResourceStringArray},
1521 {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1522 {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1523 {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1524 {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1525
1526 // AssetManager resource name/ID methods.
1527 {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1528 (void*)NativeGetResourceIdentifier},
1529 {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1530 {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1531 {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1532 {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
Winson2f3669b2019-01-11 11:28:34 -08001533 {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
1534 (void*) NativeSetResourceResolutionLoggingEnabled},
1535 {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
1536 (void*) NativeGetLastResourceResolution},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001537 {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1538 {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1539 (void*)NativeGetSizeConfigurations},
1540
1541 // Style attribute related methods.
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001542 {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001543 {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1544 {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1545 {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1546
1547 // Theme related methods.
1548 {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1549 {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1550 {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001551 {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001552 {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1553 {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1554 (void*)NativeThemeGetAttributeValue},
1555 {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1556 {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1557
1558 // AssetInputStream methods.
1559 {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1560 {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1561 {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1562 {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1563 {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1564 {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1565
1566 // System/idmap related methods.
Mårten Kongstad06a1ac82018-09-20 13:09:47 +02001567 {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
1568 (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +01001569 {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
1570 (void*)NativeGetOverlayableMap},
Ryan Mitchell2e394222019-08-28 12:10:51 -07001571 {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
1572 (void*)NativeGetOverlayablesToString},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001573
1574 // Global management/debug methods.
1575 {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1576 {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1577 {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1578};
1579
1580int register_android_content_AssetManager(JNIEnv* env) {
1581 jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1582 gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1583
1584 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1585 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1586 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1587 gTypedValueOffsets.mString =
1588 GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1589 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1590 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1591 gTypedValueOffsets.mChangingConfigurations =
1592 GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1593 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1594
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001595 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1596 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1597
1598 jclass stringClass = FindClassOrDie(env, "java/lang/String");
1599 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1600
1601 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1602 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1603 gSparseArrayOffsets.constructor =
1604 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1605 gSparseArrayOffsets.put =
1606 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1607
1608 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1609 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1610 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1611 gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1612 GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1613 gConfigurationOffsets.mScreenWidthDpOffset =
1614 GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1615 gConfigurationOffsets.mScreenHeightDpOffset =
1616 GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1617
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +01001618 jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
1619 gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
1620 gArrayMapOffsets.constructor =
1621 GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V");
1622 gArrayMapOffsets.put =
1623 GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put",
1624 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1625
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001626 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1627 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001628}
1629
1630}; // namespace android