blob: d493ddfaae13d187a8c30dc71fe9c37525b4692f [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>
21#include <linux/capability.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022#include <stdio.h>
Adam Lesinskibde1df22018-02-09 11:12:22 -080023#include <sys/stat.h>
24#include <sys/system_properties.h>
Adam Lesinskibebfcc42018-02-12 14:27:46 -080025#include <sys/types.h>
26#include <sys/wait.h>
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020027#include <unistd.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010028
Dan Albert46d84442014-11-18 16:07:51 -080029#include <private/android_filesystem_config.h> // for AID_SYSTEM
30
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020031#include <sstream>
32#include <string>
33
Adam Lesinskibebfcc42018-02-12 14:27:46 -080034#include "android-base/logging.h"
35#include "android-base/properties.h"
36#include "android-base/stringprintf.h"
37#include "android_runtime/android_util_AssetManager.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080038#include "android_runtime/AndroidRuntime.h"
39#include "android_util_Binder.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080040#include "androidfw/Asset.h"
41#include "androidfw/AssetManager.h"
42#include "androidfw/AssetManager2.h"
43#include "androidfw/AttributeResolution.h"
44#include "androidfw/MutexGuard.h"
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020045#include "androidfw/PosixUtils.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080046#include "androidfw/ResourceTypes.h"
Winson2f3669b2019-01-11 11:28:34 -080047#include "androidfw/ResourceUtils.h"
48
Dan Albert3a091b72014-11-20 15:41:25 -080049#include "core_jni_helpers.h"
50#include "jni.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080051#include "nativehelper/JNIHelp.h"
52#include "nativehelper/ScopedPrimitiveArray.h"
53#include "nativehelper/ScopedStringChars.h"
54#include "nativehelper/ScopedUtfChars.h"
Dan Albert46d84442014-11-18 16:07:51 -080055#include "utils/Log.h"
Adam Lesinski11875902017-01-23 12:58:11 -080056#include "utils/misc.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080057#include "utils/String8.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080058#include "utils/Trace.h"
Dan Albert46d84442014-11-18 16:07:51 -080059
Mårten Kongstad48d22322014-01-31 14:43:27 +010060extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
61extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
62
Adam Lesinskibebfcc42018-02-12 14:27:46 -080063using ::android::base::StringPrintf;
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020064using ::android::util::ExecuteBinary;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
66namespace android {
67
68// ----------------------------------------------------------------------------
69
Adam Lesinskibebfcc42018-02-12 14:27:46 -080070static struct typedvalue_offsets_t {
71 jfieldID mType;
72 jfieldID mData;
73 jfieldID mString;
74 jfieldID mAssetCookie;
75 jfieldID mResourceId;
76 jfieldID mChangingConfigurations;
77 jfieldID mDensity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078} gTypedValueOffsets;
79
Adam Lesinskibebfcc42018-02-12 14:27:46 -080080static struct assetfiledescriptor_offsets_t {
81 jfieldID mFd;
82 jfieldID mStartOffset;
83 jfieldID mLength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084} gAssetFileDescriptorOffsets;
85
Nicolas Geoffraya55a59a2018-05-10 15:00:13 +010086// This is also used by asset_manager.cpp.
87assetmanager_offsets_t gAssetManagerOffsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088
Adam Lesinskibebfcc42018-02-12 14:27:46 -080089static struct {
90 jfieldID native_ptr;
91} gApkAssetsFields;
92
93static struct sparsearray_offsets_t {
94 jclass classObject;
95 jmethodID constructor;
96 jmethodID put;
Adam Lesinskide898ff2014-01-29 18:20:45 -080097} gSparseArrayOffsets;
98
Adam Lesinskibebfcc42018-02-12 14:27:46 -080099static struct configuration_offsets_t {
100 jclass classObject;
101 jmethodID constructor;
102 jfieldID mSmallestScreenWidthDpOffset;
103 jfieldID mScreenWidthDpOffset;
104 jfieldID mScreenHeightDpOffset;
Filip Gruszczynski23493322015-07-29 17:02:59 -0700105} gConfigurationOffsets;
106
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800107jclass g_stringClass = nullptr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
109// ----------------------------------------------------------------------------
110
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800111// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
112constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
113 return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
114}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800116constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
117 return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118}
119
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900120// This is called by zygote (running as user root) as part of preloadResources.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800121static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
122 switch (pid_t pid = fork()) {
123 case -1:
124 PLOG(ERROR) << "failed to fork for idmap";
125 break;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900126
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800127 // child
128 case 0: {
129 struct __user_cap_header_struct capheader;
130 struct __user_cap_data_struct capdata;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900131
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800132 memset(&capheader, 0, sizeof(capheader));
133 memset(&capdata, 0, sizeof(capdata));
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900134
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800135 capheader.version = _LINUX_CAPABILITY_VERSION;
136 capheader.pid = 0;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900137
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800138 if (capget(&capheader, &capdata) != 0) {
139 PLOG(ERROR) << "capget";
140 exit(1);
141 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900142
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800143 capdata.effective = capdata.permitted;
144 if (capset(&capheader, &capdata) != 0) {
145 PLOG(ERROR) << "capset";
146 exit(1);
147 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900148
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800149 if (setgid(AID_SYSTEM) != 0) {
150 PLOG(ERROR) << "setgid";
151 exit(1);
152 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900153
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800154 if (setuid(AID_SYSTEM) != 0) {
155 PLOG(ERROR) << "setuid";
156 exit(1);
157 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900158
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800159 // Generic idmap parameters
160 const char* argv[8];
161 int argc = 0;
162 struct stat st;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900163
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800164 memset(argv, 0, sizeof(argv));
165 argv[argc++] = AssetManager::IDMAP_BIN;
166 argv[argc++] = "--scan";
167 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
168 argv[argc++] = AssetManager::TARGET_APK_PATH;
169 argv[argc++] = AssetManager::IDMAP_DIR;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900170
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800171 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200172 // use VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in
173 // addition to VENDOR_OVERLAY_DIR.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800174 std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
175 "");
176 if (!overlay_theme_path.empty()) {
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200177 overlay_theme_path =
178 std::string(AssetManager::VENDOR_OVERLAY_DIR) + "/" + overlay_theme_path;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800179 if (stat(overlay_theme_path.c_str(), &st) == 0) {
180 argv[argc++] = overlay_theme_path.c_str();
Adam Lesinskiec7f06c2018-02-09 11:01:26 -0800181 }
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800182 }
Adam Lesinski11875902017-01-23 12:58:11 -0800183
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200184 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
185 argv[argc++] = AssetManager::VENDOR_OVERLAY_DIR;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800186 }
Adam Lesinski11875902017-01-23 12:58:11 -0800187
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800188 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
189 argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
190 }
191
Dario Freni4ce46792018-06-01 14:02:08 +0100192 if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
193 argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
194 }
195
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800196 // Finally, invoke idmap (if any overlay directory exists)
197 if (argc > 5) {
198 execv(AssetManager::IDMAP_BIN, (char* const*)argv);
199 PLOG(ERROR) << "failed to execv for idmap";
200 exit(1); // should never get here
201 } else {
202 exit(0);
203 }
204 } break;
205
206 // parent
207 default:
208 waitpid(pid, nullptr, 0);
209 break;
210 }
Adam Lesinski11875902017-01-23 12:58:11 -0800211}
212
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200213static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
214 jclass /*clazz*/) {
215 // --input-directory can be given multiple times, but idmap2 expects the directory to exist
216 std::vector<std::string> input_dirs;
217 struct stat st;
218 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
219 input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
220 }
221
222 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
223 input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
224 }
225
226 if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
227 input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR);
228 }
229
230 if (input_dirs.empty()) {
231 LOG(WARNING) << "no directories for idmap2 to scan";
232 return env->NewObjectArray(0, g_stringClass, nullptr);
233 }
234
235 std::vector<std::string> argv{"/system/bin/idmap2",
236 "scan",
237 "--recursive",
238 "--target-package-name", "android",
239 "--target-apk-path", "/system/framework/framework-res.apk",
240 "--output-directory", "/data/resource-cache"};
241
242 for (const auto& dir : input_dirs) {
243 argv.push_back("--input-directory");
244 argv.push_back(dir);
245 }
246
247 const auto result = ExecuteBinary(argv);
248
249 if (!result) {
250 LOG(ERROR) << "failed to execute idmap2";
251 return nullptr;
252 }
253
254 if (result->status != 0) {
255 LOG(ERROR) << "idmap2: " << result->stderr;
256 return nullptr;
257 }
258
259 std::vector<std::string> idmap_paths;
260 std::istringstream input(result->stdout);
261 std::string path;
262 while (std::getline(input, path)) {
263 idmap_paths.push_back(path);
264 }
265
266 jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
267 if (array == nullptr) {
268 return nullptr;
269 }
270 for (size_t i = 0; i < idmap_paths.size(); i++) {
271 const std::string path = idmap_paths[i];
272 jstring java_string = env->NewStringUTF(path.c_str());
273 if (env->ExceptionCheck()) {
274 return nullptr;
275 }
276 env->SetObjectArrayElement(array, i, java_string);
277 env->DeleteLocalRef(java_string);
278 }
279 return array;
280}
281
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800282static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
283 uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
284 env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
285 env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
286 ApkAssetsCookieToJavaCookie(cookie));
287 env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
288 env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
289 env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
290 env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
291 if (config != nullptr) {
292 env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
293 }
294 return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
Adam Lesinski11875902017-01-23 12:58:11 -0800295}
296
297// ----------------------------------------------------------------------------
298
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800299// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
300struct GuardedAssetManager : public ::AAssetManager {
301 Guarded<AssetManager2> guarded_assetmanager;
Adam Lesinski11875902017-01-23 12:58:11 -0800302};
303
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800304::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
305 jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
306 ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
307 if (am == nullptr) {
308 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
309 return nullptr;
310 }
311 return am;
312}
Adam Lesinski11875902017-01-23 12:58:11 -0800313
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800314Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
315 if (assetmanager == nullptr) {
316 return nullptr;
317 }
318 return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
319}
Adam Lesinski11875902017-01-23 12:58:11 -0800320
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800321Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
322 return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
323}
Adam Lesinski11875902017-01-23 12:58:11 -0800324
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800325static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
326 return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
327}
Adam Lesinski11875902017-01-23 12:58:11 -0800328
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800329static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
330 jlongArray out_offsets) {
331 off64_t start_offset, length;
332 int fd = asset->openFileDescriptor(&start_offset, &length);
333 asset.reset();
Adam Lesinski11875902017-01-23 12:58:11 -0800334
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800335 if (fd < 0) {
336 jniThrowException(env, "java/io/FileNotFoundException",
337 "This file can not be opened as a file descriptor; it is probably "
338 "compressed");
339 return nullptr;
340 }
Adam Lesinski11875902017-01-23 12:58:11 -0800341
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800342 jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
343 if (offsets == nullptr) {
344 close(fd);
345 return nullptr;
346 }
347
348 offsets[0] = start_offset;
349 offsets[1] = length;
350
351 env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
352
353 jobject file_desc = jniCreateFileDescriptor(env, fd);
354 if (file_desc == nullptr) {
355 close(fd);
356 return nullptr;
357 }
358 return newParcelFileDescriptor(env, file_desc);
359}
360
361static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
362 return Asset::getGlobalCount();
363}
364
365static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
366 String8 alloc = Asset::getAssetAllocations();
367 if (alloc.length() <= 0) {
368 return nullptr;
369 }
370 return env->NewStringUTF(alloc.string());
371}
372
373static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
374 // TODO(adamlesinski): Switch to AssetManager2.
375 return AssetManager::getGlobalCount();
376}
377
378static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
379 // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
380 // AssetManager2 in a contiguous block (GuardedAssetManager).
381 return reinterpret_cast<jlong>(new GuardedAssetManager());
382}
383
384static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
385 delete reinterpret_cast<GuardedAssetManager*>(ptr);
386}
387
388static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
389 jobjectArray apk_assets_array, jboolean invalidate_caches) {
390 ATRACE_NAME("AssetManager::SetApkAssets");
391
392 const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
393 std::vector<const ApkAssets*> apk_assets;
394 apk_assets.reserve(apk_assets_len);
395 for (jsize i = 0; i < apk_assets_len; i++) {
396 jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
397 if (obj == nullptr) {
398 std::string msg = StringPrintf("ApkAssets at index %d is null", i);
399 jniThrowNullPointerException(env, msg.c_str());
400 return;
401 }
402
403 jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
404 if (env->ExceptionCheck()) {
405 return;
406 }
407 apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
408 }
409
410 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
411 assetmanager->SetApkAssets(apk_assets, invalidate_caches);
412}
413
414static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
415 jstring locale, jint orientation, jint touchscreen, jint density,
416 jint keyboard, jint keyboard_hidden, jint navigation,
417 jint screen_width, jint screen_height,
418 jint smallest_screen_width_dp, jint screen_width_dp,
419 jint screen_height_dp, jint screen_layout, jint ui_mode,
420 jint color_mode, jint major_version) {
421 ATRACE_NAME("AssetManager::SetConfiguration");
422
423 ResTable_config configuration;
424 memset(&configuration, 0, sizeof(configuration));
425 configuration.mcc = static_cast<uint16_t>(mcc);
426 configuration.mnc = static_cast<uint16_t>(mnc);
427 configuration.orientation = static_cast<uint8_t>(orientation);
428 configuration.touchscreen = static_cast<uint8_t>(touchscreen);
429 configuration.density = static_cast<uint16_t>(density);
430 configuration.keyboard = static_cast<uint8_t>(keyboard);
431 configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
432 configuration.navigation = static_cast<uint8_t>(navigation);
433 configuration.screenWidth = static_cast<uint16_t>(screen_width);
434 configuration.screenHeight = static_cast<uint16_t>(screen_height);
435 configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
436 configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
437 configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
438 configuration.screenLayout = static_cast<uint8_t>(screen_layout);
439 configuration.uiMode = static_cast<uint8_t>(ui_mode);
440 configuration.colorMode = static_cast<uint8_t>(color_mode);
441 configuration.sdkVersion = static_cast<uint16_t>(major_version);
442
443 if (locale != nullptr) {
444 ScopedUtfChars locale_utf8(env, locale);
445 CHECK(locale_utf8.c_str() != nullptr);
446 configuration.setBcp47Locale(locale_utf8.c_str());
447 }
448
449 // Constants duplicated from Java class android.content.res.Configuration.
450 static const jint kScreenLayoutRoundMask = 0x300;
451 static const jint kScreenLayoutRoundShift = 8;
452
453 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
454 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
455 // into screenLayout2.
456 configuration.screenLayout2 =
457 static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
458
459 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
460 assetmanager->SetConfiguration(configuration);
461}
462
463static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
464 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
465
466 jobject sparse_array =
467 env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
468
469 if (sparse_array == nullptr) {
470 // An exception is pending.
471 return nullptr;
472 }
473
474 assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
475 jstring jpackage_name = env->NewStringUTF(package_name.c_str());
476 if (jpackage_name == nullptr) {
477 // An exception is pending.
478 return;
479 }
480
481 env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
482 jpackage_name);
483 });
484 return sparse_array;
485}
486
487static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
488 ScopedUtfChars path_utf8(env, path);
489 if (path_utf8.c_str() == nullptr) {
490 // This will throw NPE.
491 return nullptr;
492 }
493
494 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
495 std::unique_ptr<AssetDir> asset_dir =
496 assetmanager->OpenDir(path_utf8.c_str());
497 if (asset_dir == nullptr) {
498 jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
499 return nullptr;
500 }
501
502 const size_t file_count = asset_dir->getFileCount();
503
504 jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
505 if (array == nullptr) {
506 return nullptr;
507 }
508
509 for (size_t i = 0; i < file_count; i++) {
510 jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
511
512 // Check for errors creating the strings (if malformed or no memory).
513 if (env->ExceptionCheck()) {
514 return nullptr;
515 }
516
517 env->SetObjectArrayElement(array, i, java_string);
518
519 // If we have a large amount of string in our array, we might overflow the
520 // local reference table of the VM.
521 env->DeleteLocalRef(java_string);
522 }
523 return array;
524}
525
526static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
527 jint access_mode) {
528 ScopedUtfChars asset_path_utf8(env, asset_path);
529 if (asset_path_utf8.c_str() == nullptr) {
530 // This will throw NPE.
531 return 0;
532 }
533
534 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
535
536 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
537 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
538 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
539 return 0;
540 }
541
542 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
543 std::unique_ptr<Asset> asset =
544 assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
545 if (!asset) {
546 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
547 return 0;
548 }
549 return reinterpret_cast<jlong>(asset.release());
550}
551
552static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
553 jlongArray out_offsets) {
554 ScopedUtfChars asset_path_utf8(env, asset_path);
555 if (asset_path_utf8.c_str() == nullptr) {
556 // This will throw NPE.
557 return nullptr;
558 }
559
560 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
561
562 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
563 std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
564 if (!asset) {
565 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
566 return nullptr;
567 }
568 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
569}
570
571static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
572 jstring asset_path, jint access_mode) {
573 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
574 ScopedUtfChars asset_path_utf8(env, asset_path);
575 if (asset_path_utf8.c_str() == nullptr) {
576 // This will throw NPE.
577 return 0;
578 }
579
580 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
581
582 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
583 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
584 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
585 return 0;
586 }
587
588 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
589 std::unique_ptr<Asset> asset;
590 if (cookie != kInvalidCookie) {
591 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
592 static_cast<Asset::AccessMode>(access_mode));
593 } else {
594 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
595 static_cast<Asset::AccessMode>(access_mode));
596 }
597
598 if (!asset) {
599 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
600 return 0;
601 }
602 return reinterpret_cast<jlong>(asset.release());
603}
604
605static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
606 jstring asset_path, jlongArray out_offsets) {
607 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
608 ScopedUtfChars asset_path_utf8(env, asset_path);
609 if (asset_path_utf8.c_str() == nullptr) {
610 // This will throw NPE.
611 return nullptr;
612 }
613
614 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
615
616 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
617 std::unique_ptr<Asset> asset;
618 if (cookie != kInvalidCookie) {
619 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
620 } else {
621 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
622 }
623
624 if (!asset) {
625 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
626 return nullptr;
627 }
628 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
629}
630
631static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
632 jstring asset_path) {
633 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
634 ScopedUtfChars asset_path_utf8(env, asset_path);
635 if (asset_path_utf8.c_str() == nullptr) {
636 // This will throw NPE.
637 return 0;
638 }
639
640 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
641
642 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
643 std::unique_ptr<Asset> asset;
644 if (cookie != kInvalidCookie) {
645 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
646 } else {
647 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
648 }
649
650 if (!asset) {
651 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
652 return 0;
653 }
654
655 // May be nullptr.
656 const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
657
658 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
659 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
660 asset.reset();
661
662 if (err != NO_ERROR) {
663 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
664 return 0;
665 }
666 return reinterpret_cast<jlong>(xml_tree.release());
667}
668
669static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
670 jshort density, jobject typed_value,
671 jboolean resolve_references) {
672 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
673 Res_value value;
674 ResTable_config selected_config;
675 uint32_t flags;
676 ApkAssetsCookie cookie =
677 assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
678 static_cast<uint16_t>(density), &value, &selected_config, &flags);
679 if (cookie == kInvalidCookie) {
680 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
681 }
682
683 uint32_t ref = static_cast<uint32_t>(resid);
684 if (resolve_references) {
685 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
686 if (cookie == kInvalidCookie) {
687 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
688 }
689 }
690 return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
691}
692
693static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
694 jint bag_entry_id, jobject typed_value) {
695 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
696 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
697 if (bag == nullptr) {
698 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
699 }
700
701 uint32_t type_spec_flags = bag->type_spec_flags;
702 ApkAssetsCookie cookie = kInvalidCookie;
703 const Res_value* bag_value = nullptr;
704 for (const ResolvedBag::Entry& entry : bag) {
705 if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
706 cookie = entry.cookie;
707 bag_value = &entry.value;
708
709 // Keep searching (the old implementation did that).
710 }
711 }
712
713 if (cookie == kInvalidCookie) {
714 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
715 }
716
717 Res_value value = *bag_value;
718 uint32_t ref = static_cast<uint32_t>(resid);
719 ResTable_config selected_config;
720 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
721 if (cookie == kInvalidCookie) {
722 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
723 }
724 return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
725}
726
727static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
728 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
729 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
730 if (bag == nullptr) {
731 return nullptr;
732 }
733
734 jintArray array = env->NewIntArray(bag->entry_count);
735 if (env->ExceptionCheck()) {
736 return nullptr;
737 }
738
739 for (uint32_t i = 0; i < bag->entry_count; i++) {
740 jint attr_resid = bag->entries[i].key;
741 env->SetIntArrayRegion(array, i, 1, &attr_resid);
742 }
743 return array;
744}
745
746static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
747 jint resid) {
748 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
749 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
750 if (bag == nullptr) {
751 return nullptr;
752 }
753
754 jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
755 if (array == nullptr) {
756 return nullptr;
757 }
758
759 for (uint32_t i = 0; i < bag->entry_count; i++) {
760 const ResolvedBag::Entry& entry = bag->entries[i];
761
762 // Resolve any references to their final value.
763 Res_value value = entry.value;
764 ResTable_config selected_config;
765 uint32_t flags;
766 uint32_t ref;
767 ApkAssetsCookie cookie =
768 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
769 if (cookie == kInvalidCookie) {
770 return nullptr;
771 }
772
773 if (value.dataType == Res_value::TYPE_STRING) {
774 const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
775 const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
776
777 jstring java_string = nullptr;
778 size_t str_len;
779 const char* str_utf8 = pool->string8At(value.data, &str_len);
780 if (str_utf8 != nullptr) {
781 java_string = env->NewStringUTF(str_utf8);
782 } else {
783 const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
784 java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
785 }
786
787 // Check for errors creating the strings (if malformed or no memory).
788 if (env->ExceptionCheck()) {
789 return nullptr;
790 }
791
792 env->SetObjectArrayElement(array, i, java_string);
793
794 // If we have a large amount of string in our array, we might overflow the
795 // local reference table of the VM.
796 env->DeleteLocalRef(java_string);
797 }
798 }
799 return array;
800}
801
802static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
803 jint resid) {
804 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
805 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
806 if (bag == nullptr) {
807 return nullptr;
808 }
809
810 jintArray array = env->NewIntArray(bag->entry_count * 2);
811 if (array == nullptr) {
812 return nullptr;
813 }
814
815 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
816 if (buffer == nullptr) {
817 return nullptr;
818 }
819
820 for (size_t i = 0; i < bag->entry_count; i++) {
821 const ResolvedBag::Entry& entry = bag->entries[i];
822 Res_value value = entry.value;
823 ResTable_config selected_config;
824 uint32_t flags;
825 uint32_t ref;
826 ApkAssetsCookie cookie =
827 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
828 if (cookie == kInvalidCookie) {
829 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
830 return nullptr;
831 }
832
833 jint string_index = -1;
834 if (value.dataType == Res_value::TYPE_STRING) {
835 string_index = static_cast<jint>(value.data);
836 }
837
838 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
839 buffer[(i * 2) + 1] = string_index;
840 }
841 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
842 return array;
843}
844
845static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
846 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
847 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
848 if (bag == nullptr) {
849 return nullptr;
850 }
851
852 jintArray array = env->NewIntArray(bag->entry_count);
853 if (array == nullptr) {
854 return nullptr;
855 }
856
857 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
858 if (buffer == nullptr) {
859 return nullptr;
860 }
861
862 for (size_t i = 0; i < bag->entry_count; i++) {
863 const ResolvedBag::Entry& entry = bag->entries[i];
864 Res_value value = entry.value;
865 ResTable_config selected_config;
866 uint32_t flags;
867 uint32_t ref;
868 ApkAssetsCookie cookie =
869 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
870 if (cookie == kInvalidCookie) {
871 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
872 return nullptr;
873 }
874
875 if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
876 buffer[i] = static_cast<jint>(value.data);
877 }
878 }
879 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
880 return array;
881}
882
883static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
884 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
885 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
886 if (bag == nullptr) {
887 return -1;
888 }
889 return static_cast<jint>(bag->entry_count);
890}
891
892static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
893 jintArray out_data) {
894 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
895 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
896 if (bag == nullptr) {
897 return -1;
898 }
899
900 const jsize out_data_length = env->GetArrayLength(out_data);
901 if (env->ExceptionCheck()) {
902 return -1;
903 }
904
905 if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
906 jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
907 return -1;
908 }
909
910 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
911 if (buffer == nullptr) {
912 return -1;
913 }
914
915 jint* cursor = buffer;
916 for (size_t i = 0; i < bag->entry_count; i++) {
917 const ResolvedBag::Entry& entry = bag->entries[i];
918 Res_value value = entry.value;
919 ResTable_config selected_config;
920 selected_config.density = 0;
921 uint32_t flags = bag->type_spec_flags;
Todd Kennedy1d63cc32018-04-18 10:25:45 -0700922 uint32_t ref = 0;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800923 ApkAssetsCookie cookie =
924 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
925 if (cookie == kInvalidCookie) {
926 env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
927 return -1;
928 }
929
930 // Deal with the special @null value -- it turns back to TYPE_NULL.
931 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
932 value.dataType = Res_value::TYPE_NULL;
933 value.data = Res_value::DATA_NULL_UNDEFINED;
934 }
935
936 cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
937 cursor[STYLE_DATA] = static_cast<jint>(value.data);
938 cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
939 cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
940 cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
941 cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
942 cursor += STYLE_NUM_ENTRIES;
943 }
944 env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
945 return static_cast<jint>(bag->entry_count);
946}
947
948static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
949 jstring def_type, jstring def_package) {
950 ScopedUtfChars name_utf8(env, name);
951 if (name_utf8.c_str() == nullptr) {
952 // This will throw NPE.
953 return 0;
954 }
955
956 std::string type;
957 if (def_type != nullptr) {
958 ScopedUtfChars type_utf8(env, def_type);
959 CHECK(type_utf8.c_str() != nullptr);
960 type = type_utf8.c_str();
961 }
962
963 std::string package;
964 if (def_package != nullptr) {
965 ScopedUtfChars package_utf8(env, def_package);
966 CHECK(package_utf8.c_str() != nullptr);
967 package = package_utf8.c_str();
968 }
969 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
970 return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
971}
972
973static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
974 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
975 AssetManager2::ResourceName name;
976 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
977 return nullptr;
978 }
979
Winson2f3669b2019-01-11 11:28:34 -0800980 std::string result = ToFormattedResourceString(&name);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800981 return env->NewStringUTF(result.c_str());
982}
983
984static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
985 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
986 AssetManager2::ResourceName name;
987 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
988 return nullptr;
989 }
990
991 if (name.package != nullptr) {
992 return env->NewStringUTF(name.package);
993 }
994 return nullptr;
995}
996
997static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
998 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
999 AssetManager2::ResourceName name;
1000 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1001 return nullptr;
1002 }
1003
1004 if (name.type != nullptr) {
1005 return env->NewStringUTF(name.type);
1006 } else if (name.type16 != nullptr) {
1007 return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
1008 }
1009 return nullptr;
1010}
1011
1012static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1013 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1014 AssetManager2::ResourceName name;
1015 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1016 return nullptr;
1017 }
1018
1019 if (name.entry != nullptr) {
1020 return env->NewStringUTF(name.entry);
1021 } else if (name.entry16 != nullptr) {
1022 return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
1023 }
1024 return nullptr;
1025}
1026
Winson2f3669b2019-01-11 11:28:34 -08001027static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
1028 jclass /*clazz*/,
1029 jlong ptr,
1030 jboolean enabled) {
1031 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1032 assetmanager->SetResourceResolutionLoggingEnabled(enabled);
1033}
1034
1035static jstring NativeGetLastResourceResolution(JNIEnv* env,
1036 jclass /*clazz*/,
1037 jlong ptr) {
1038 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1039 std::string resolution = assetmanager->GetLastResourceResolution();
1040 if (resolution.empty()) {
1041 return nullptr;
1042 } else {
1043 return env->NewStringUTF(resolution.c_str());
1044 }
1045}
1046
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001047static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
1048 jboolean exclude_system) {
1049 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1050 std::set<std::string> locales =
1051 assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
1052
1053 jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
1054 if (array == nullptr) {
1055 return nullptr;
1056 }
1057
1058 size_t idx = 0;
1059 for (const std::string& locale : locales) {
1060 jstring java_string = env->NewStringUTF(locale.c_str());
1061 if (java_string == nullptr) {
1062 return nullptr;
1063 }
1064 env->SetObjectArrayElement(array, idx++, java_string);
1065 env->DeleteLocalRef(java_string);
1066 }
1067 return array;
1068}
1069
1070static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
1071 jobject result =
1072 env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1073 if (result == nullptr) {
1074 return nullptr;
1075 }
1076
1077 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1078 config.smallestScreenWidthDp);
1079 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1080 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1081 return result;
1082}
1083
1084static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1085 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1086 std::set<ResTable_config> configurations =
1087 assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1088
1089 jobjectArray array =
1090 env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1091 if (array == nullptr) {
1092 return nullptr;
1093 }
1094
1095 size_t idx = 0;
1096 for (const ResTable_config& configuration : configurations) {
1097 jobject java_configuration = ConstructConfigurationObject(env, configuration);
1098 if (java_configuration == nullptr) {
1099 return nullptr;
1100 }
1101
1102 env->SetObjectArrayElement(array, idx++, java_configuration);
1103 env->DeleteLocalRef(java_configuration);
1104 }
1105 return array;
1106}
1107
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001108static jintArray NativeAttributeResolutionStack(
1109 JNIEnv* env, jclass /*clazz*/, jlong ptr,
1110 jlong theme_ptr, jint xml_style_res,
1111 jint def_style_attr, jint def_style_resid) {
1112
1113 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1114 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1115 CHECK(theme->GetAssetManager() == &(*assetmanager));
1116 (void) assetmanager;
1117
1118 // Load default style from attribute, if specified...
1119 uint32_t def_style_flags = 0u;
1120 if (def_style_attr != 0) {
1121 Res_value value;
1122 if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
1123 if (value.dataType == Res_value::TYPE_REFERENCE) {
1124 def_style_resid = value.data;
1125 }
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
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001148static 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 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(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
1172static 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 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1227 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1228 CHECK(theme->GetAssetManager() == &(*assetmanager));
1229 (void) assetmanager;
1230
1231 bool result = ResolveAttrs(
1232 theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1233 reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1234 attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1235 if (out_indices != nullptr) {
1236 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1237 }
1238
1239 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1240 if (values != nullptr) {
1241 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1242 }
1243 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1244 return result ? JNI_TRUE : JNI_FALSE;
1245}
1246
1247static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1248 jlong xml_parser_ptr, jintArray java_attrs,
1249 jintArray out_java_values, jintArray out_java_indices) {
1250 const jsize attrs_len = env->GetArrayLength(java_attrs);
1251 const jsize out_values_len = env->GetArrayLength(out_java_values);
1252 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1253 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1254 return JNI_FALSE;
1255 }
1256
1257 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1258 if (attrs == nullptr) {
1259 return JNI_FALSE;
1260 }
1261
1262 jint* out_values =
1263 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1264 if (out_values == nullptr) {
1265 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1266 return JNI_FALSE;
1267 }
1268
1269 jint* out_indices = nullptr;
1270 if (out_java_indices != nullptr) {
1271 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1272 if (out_indices_len > attrs_len) {
1273 out_indices =
1274 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1275 if (out_indices == nullptr) {
1276 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1277 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1278 return JNI_FALSE;
1279 }
1280 }
1281 }
1282
1283 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1284 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1285
1286 bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1287 reinterpret_cast<uint32_t*>(attrs), attrs_len,
1288 reinterpret_cast<uint32_t*>(out_values),
1289 reinterpret_cast<uint32_t*>(out_indices));
1290
1291 if (out_indices != nullptr) {
1292 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1293 }
1294 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1295 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1296 return result ? JNI_TRUE : JNI_FALSE;
1297}
1298
1299static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1300 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1301 return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1302}
1303
1304static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1305 delete reinterpret_cast<Theme*>(theme_ptr);
1306}
1307
1308static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1309 jint resid, jboolean force) {
1310 // AssetManager is accessed via the theme, so grab an explicit lock here.
1311 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1312 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1313 CHECK(theme->GetAssetManager() == &(*assetmanager));
1314 (void) assetmanager;
1315 theme->ApplyStyle(static_cast<uint32_t>(resid), force);
1316
1317 // TODO(adamlesinski): Consider surfacing exception when result is failure.
1318 // CTS currently expects no exceptions from this method.
1319 // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1320 // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
1321}
1322
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001323static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1324 jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001325 Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1326 Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001327
1328 if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1329 ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
1330 CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
1331 (void) dst_assetmanager;
1332
1333 ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
1334 CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
1335 (void) src_assetmanager;
1336
1337 dst_theme->SetTo(*src_theme);
1338 } else {
1339 dst_theme->SetTo(*src_theme);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001340 }
1341}
1342
1343static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1344 reinterpret_cast<Theme*>(theme_ptr)->Clear();
1345}
1346
1347static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1348 jint resid, jobject typed_value,
1349 jboolean resolve_references) {
1350 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1351 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1352 CHECK(theme->GetAssetManager() == &(*assetmanager));
1353 (void) assetmanager;
1354
1355 Res_value value;
1356 uint32_t flags;
1357 ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1358 if (cookie == kInvalidCookie) {
1359 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1360 }
1361
1362 uint32_t ref = 0u;
1363 if (resolve_references) {
1364 ResTable_config selected_config;
1365 cookie =
1366 theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1367 if (cookie == kInvalidCookie) {
1368 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1369 }
1370 }
1371 return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1372}
1373
1374static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1375 jint priority, jstring tag, jstring prefix) {
1376 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1377 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1378 CHECK(theme->GetAssetManager() == &(*assetmanager));
1379 (void) assetmanager;
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001380 (void) priority;
1381 (void) tag;
1382 (void) prefix;
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001383
1384 theme->Dump();
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001385}
1386
1387static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1388 jlong theme_ptr) {
1389 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1390 return static_cast<jint>(theme->GetChangingConfigurations());
1391}
1392
1393static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1394 delete reinterpret_cast<Asset*>(asset_ptr);
1395}
1396
1397static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1398 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1399 uint8_t b;
1400 ssize_t res = asset->read(&b, sizeof(b));
1401 return res == sizeof(b) ? static_cast<jint>(b) : -1;
1402}
1403
1404static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1405 jint offset, jint len) {
1406 if (len == 0) {
1407 return 0;
1408 }
1409
1410 jsize buffer_len = env->GetArrayLength(java_buffer);
1411 if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1412 offset > buffer_len - len) {
1413 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1414 return -1;
1415 }
1416
1417 ScopedByteArrayRW byte_array(env, java_buffer);
1418 if (byte_array.get() == nullptr) {
1419 return -1;
1420 }
1421
1422 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1423 ssize_t res = asset->read(byte_array.get() + offset, len);
1424 if (res < 0) {
1425 jniThrowException(env, "java/io/IOException", "");
1426 return -1;
1427 }
1428 return res > 0 ? static_cast<jint>(res) : -1;
1429}
1430
1431static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1432 jint whence) {
1433 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1434 return static_cast<jlong>(asset->seek(
1435 static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1436}
1437
1438static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1439 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1440 return static_cast<jlong>(asset->getLength());
1441}
1442
1443static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1444 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1445 return static_cast<jlong>(asset->getRemainingLength());
1446}
1447
1448// ----------------------------------------------------------------------------
1449
1450// JNI registration.
1451static const JNINativeMethod gAssetManagerMethods[] = {
1452 // AssetManager setup methods.
1453 {"nativeCreate", "()J", (void*)NativeCreate},
1454 {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1455 {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1456 {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1457 (void*)NativeSetConfiguration},
1458 {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
1459 (void*)NativeGetAssignedPackageIdentifiers},
1460
1461 // AssetManager file methods.
1462 {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1463 {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1464 {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1465 (void*)NativeOpenAssetFd},
1466 {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1467 {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1468 (void*)NativeOpenNonAssetFd},
1469 {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
1470
1471 // AssetManager resource methods.
1472 {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1473 {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1474 (void*)NativeGetResourceBagValue},
1475 {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1476 {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1477 (void*)NativeGetResourceStringArray},
1478 {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1479 {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1480 {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1481 {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1482
1483 // AssetManager resource name/ID methods.
1484 {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1485 (void*)NativeGetResourceIdentifier},
1486 {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1487 {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1488 {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1489 {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
Winson2f3669b2019-01-11 11:28:34 -08001490 {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
1491 (void*) NativeSetResourceResolutionLoggingEnabled},
1492 {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
1493 (void*) NativeGetLastResourceResolution},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001494 {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1495 {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1496 (void*)NativeGetSizeConfigurations},
1497
1498 // Style attribute related methods.
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001499 {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001500 {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1501 {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1502 {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1503
1504 // Theme related methods.
1505 {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1506 {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1507 {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001508 {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001509 {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1510 {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1511 (void*)NativeThemeGetAttributeValue},
1512 {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1513 {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1514
1515 // AssetInputStream methods.
1516 {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1517 {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1518 {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1519 {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1520 {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1521 {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1522
1523 // System/idmap related methods.
1524 {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
Mårten Kongstad06a1ac82018-09-20 13:09:47 +02001525 {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
1526 (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001527
1528 // Global management/debug methods.
1529 {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1530 {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1531 {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1532};
1533
1534int register_android_content_AssetManager(JNIEnv* env) {
1535 jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1536 gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1537
1538 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1539 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1540 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1541 gTypedValueOffsets.mString =
1542 GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1543 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1544 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1545 gTypedValueOffsets.mChangingConfigurations =
1546 GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1547 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1548
1549 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1550 gAssetFileDescriptorOffsets.mFd =
1551 GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1552 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1553 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1554
1555 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1556 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1557
1558 jclass stringClass = FindClassOrDie(env, "java/lang/String");
1559 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1560
1561 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1562 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1563 gSparseArrayOffsets.constructor =
1564 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1565 gSparseArrayOffsets.put =
1566 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1567
1568 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1569 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1570 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1571 gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1572 GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1573 gConfigurationOffsets.mScreenWidthDpOffset =
1574 GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1575 gConfigurationOffsets.mScreenHeightDpOffset =
1576 GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1577
1578 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1579 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580}
1581
1582}; // namespace android