blob: 7b564ae162ce61fc53986724e46112331fe6fcdb [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"
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
Adam Lesinskibebfcc42018-02-12 14:27:46 -080078static struct assetfiledescriptor_offsets_t {
79 jfieldID mFd;
80 jfieldID mStartOffset;
81 jfieldID mLength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082} gAssetFileDescriptorOffsets;
83
Nicolas Geoffraya55a59a2018-05-10 15:00:13 +010084// This is also used by asset_manager.cpp.
85assetmanager_offsets_t gAssetManagerOffsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Adam Lesinskibebfcc42018-02-12 14:27:46 -080087static struct {
88 jfieldID native_ptr;
89} gApkAssetsFields;
90
91static struct sparsearray_offsets_t {
92 jclass classObject;
93 jmethodID constructor;
94 jmethodID put;
Adam Lesinskide898ff2014-01-29 18:20:45 -080095} gSparseArrayOffsets;
96
Adam Lesinskibebfcc42018-02-12 14:27:46 -080097static struct configuration_offsets_t {
98 jclass classObject;
99 jmethodID constructor;
100 jfieldID mSmallestScreenWidthDpOffset;
101 jfieldID mScreenWidthDpOffset;
102 jfieldID mScreenHeightDpOffset;
Filip Gruszczynski23493322015-07-29 17:02:59 -0700103} gConfigurationOffsets;
104
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800105jclass 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
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900118// This is called by zygote (running as user root) as part of preloadResources.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800119static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
120 switch (pid_t pid = fork()) {
121 case -1:
122 PLOG(ERROR) << "failed to fork for idmap";
123 break;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900124
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800125 // child
126 case 0: {
127 struct __user_cap_header_struct capheader;
128 struct __user_cap_data_struct capdata;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900129
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800130 memset(&capheader, 0, sizeof(capheader));
131 memset(&capdata, 0, sizeof(capdata));
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900132
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800133 capheader.version = _LINUX_CAPABILITY_VERSION;
134 capheader.pid = 0;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900135
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800136 if (capget(&capheader, &capdata) != 0) {
137 PLOG(ERROR) << "capget";
138 exit(1);
139 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900140
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800141 capdata.effective = capdata.permitted;
142 if (capset(&capheader, &capdata) != 0) {
143 PLOG(ERROR) << "capset";
144 exit(1);
145 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900146
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800147 if (setgid(AID_SYSTEM) != 0) {
148 PLOG(ERROR) << "setgid";
149 exit(1);
150 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900151
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800152 if (setuid(AID_SYSTEM) != 0) {
153 PLOG(ERROR) << "setuid";
154 exit(1);
155 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900156
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800157 // Generic idmap parameters
158 const char* argv[8];
159 int argc = 0;
160 struct stat st;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900161
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800162 memset(argv, 0, sizeof(argv));
163 argv[argc++] = AssetManager::IDMAP_BIN;
164 argv[argc++] = "--scan";
165 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
166 argv[argc++] = AssetManager::TARGET_APK_PATH;
167 argv[argc++] = AssetManager::IDMAP_DIR;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900168
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800169 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200170 // use VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in
171 // addition to VENDOR_OVERLAY_DIR.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800172 std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
173 "");
174 if (!overlay_theme_path.empty()) {
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200175 overlay_theme_path =
176 std::string(AssetManager::VENDOR_OVERLAY_DIR) + "/" + overlay_theme_path;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800177 if (stat(overlay_theme_path.c_str(), &st) == 0) {
178 argv[argc++] = overlay_theme_path.c_str();
Adam Lesinskiec7f06c2018-02-09 11:01:26 -0800179 }
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800180 }
Adam Lesinski11875902017-01-23 12:58:11 -0800181
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200182 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
183 argv[argc++] = AssetManager::VENDOR_OVERLAY_DIR;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800184 }
Adam Lesinski11875902017-01-23 12:58:11 -0800185
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800186 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
187 argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
188 }
189
Dario Freni4ce46792018-06-01 14:02:08 +0100190 if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
191 argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
192 }
193
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800194 // Finally, invoke idmap (if any overlay directory exists)
195 if (argc > 5) {
196 execv(AssetManager::IDMAP_BIN, (char* const*)argv);
197 PLOG(ERROR) << "failed to execv for idmap";
198 exit(1); // should never get here
199 } else {
200 exit(0);
201 }
202 } break;
203
204 // parent
205 default:
206 waitpid(pid, nullptr, 0);
207 break;
208 }
Adam Lesinski11875902017-01-23 12:58:11 -0800209}
210
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200211static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
212 jclass /*clazz*/) {
213 // --input-directory can be given multiple times, but idmap2 expects the directory to exist
214 std::vector<std::string> input_dirs;
215 struct stat st;
216 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
217 input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
218 }
219
220 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
221 input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
222 }
223
224 if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
225 input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR);
226 }
227
228 if (input_dirs.empty()) {
229 LOG(WARNING) << "no directories for idmap2 to scan";
230 return env->NewObjectArray(0, g_stringClass, nullptr);
231 }
232
233 std::vector<std::string> argv{"/system/bin/idmap2",
234 "scan",
235 "--recursive",
236 "--target-package-name", "android",
237 "--target-apk-path", "/system/framework/framework-res.apk",
238 "--output-directory", "/data/resource-cache"};
239
240 for (const auto& dir : input_dirs) {
241 argv.push_back("--input-directory");
242 argv.push_back(dir);
243 }
244
245 const auto result = ExecuteBinary(argv);
246
247 if (!result) {
248 LOG(ERROR) << "failed to execute idmap2";
249 return nullptr;
250 }
251
252 if (result->status != 0) {
253 LOG(ERROR) << "idmap2: " << result->stderr;
254 return nullptr;
255 }
256
257 std::vector<std::string> idmap_paths;
258 std::istringstream input(result->stdout);
259 std::string path;
260 while (std::getline(input, path)) {
261 idmap_paths.push_back(path);
262 }
263
264 jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
265 if (array == nullptr) {
266 return nullptr;
267 }
268 for (size_t i = 0; i < idmap_paths.size(); i++) {
269 const std::string path = idmap_paths[i];
270 jstring java_string = env->NewStringUTF(path.c_str());
271 if (env->ExceptionCheck()) {
272 return nullptr;
273 }
274 env->SetObjectArrayElement(array, i, java_string);
275 env->DeleteLocalRef(java_string);
276 }
277 return array;
278}
279
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800280static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
281 uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
282 env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
283 env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
284 ApkAssetsCookieToJavaCookie(cookie));
285 env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
286 env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
287 env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
288 env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
289 if (config != nullptr) {
290 env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
291 }
292 return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
Adam Lesinski11875902017-01-23 12:58:11 -0800293}
294
295// ----------------------------------------------------------------------------
296
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800297// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
298struct GuardedAssetManager : public ::AAssetManager {
299 Guarded<AssetManager2> guarded_assetmanager;
Adam Lesinski11875902017-01-23 12:58:11 -0800300};
301
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800302::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
303 jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
304 ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
305 if (am == nullptr) {
306 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
307 return nullptr;
308 }
309 return am;
310}
Adam Lesinski11875902017-01-23 12:58:11 -0800311
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800312Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
313 if (assetmanager == nullptr) {
314 return nullptr;
315 }
316 return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
317}
Adam Lesinski11875902017-01-23 12:58:11 -0800318
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800319Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
320 return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
321}
Adam Lesinski11875902017-01-23 12:58:11 -0800322
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800323static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
324 return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
325}
Adam Lesinski11875902017-01-23 12:58:11 -0800326
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800327static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
328 jlongArray out_offsets) {
329 off64_t start_offset, length;
330 int fd = asset->openFileDescriptor(&start_offset, &length);
331 asset.reset();
Adam Lesinski11875902017-01-23 12:58:11 -0800332
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800333 if (fd < 0) {
334 jniThrowException(env, "java/io/FileNotFoundException",
335 "This file can not be opened as a file descriptor; it is probably "
336 "compressed");
337 return nullptr;
338 }
Adam Lesinski11875902017-01-23 12:58:11 -0800339
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800340 jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
341 if (offsets == nullptr) {
342 close(fd);
343 return nullptr;
344 }
345
346 offsets[0] = start_offset;
347 offsets[1] = length;
348
349 env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
350
351 jobject file_desc = jniCreateFileDescriptor(env, fd);
352 if (file_desc == nullptr) {
353 close(fd);
354 return nullptr;
355 }
356 return newParcelFileDescriptor(env, file_desc);
357}
358
359static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
360 return Asset::getGlobalCount();
361}
362
363static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
364 String8 alloc = Asset::getAssetAllocations();
365 if (alloc.length() <= 0) {
366 return nullptr;
367 }
368 return env->NewStringUTF(alloc.string());
369}
370
371static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
372 // TODO(adamlesinski): Switch to AssetManager2.
373 return AssetManager::getGlobalCount();
374}
375
376static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
377 // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
378 // AssetManager2 in a contiguous block (GuardedAssetManager).
379 return reinterpret_cast<jlong>(new GuardedAssetManager());
380}
381
382static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
383 delete reinterpret_cast<GuardedAssetManager*>(ptr);
384}
385
386static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
387 jobjectArray apk_assets_array, jboolean invalidate_caches) {
388 ATRACE_NAME("AssetManager::SetApkAssets");
389
390 const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
391 std::vector<const ApkAssets*> apk_assets;
392 apk_assets.reserve(apk_assets_len);
393 for (jsize i = 0; i < apk_assets_len; i++) {
394 jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
395 if (obj == nullptr) {
396 std::string msg = StringPrintf("ApkAssets at index %d is null", i);
397 jniThrowNullPointerException(env, msg.c_str());
398 return;
399 }
400
401 jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
402 if (env->ExceptionCheck()) {
403 return;
404 }
405 apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
406 }
407
408 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
409 assetmanager->SetApkAssets(apk_assets, invalidate_caches);
410}
411
412static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
413 jstring locale, jint orientation, jint touchscreen, jint density,
414 jint keyboard, jint keyboard_hidden, jint navigation,
415 jint screen_width, jint screen_height,
416 jint smallest_screen_width_dp, jint screen_width_dp,
417 jint screen_height_dp, jint screen_layout, jint ui_mode,
418 jint color_mode, jint major_version) {
419 ATRACE_NAME("AssetManager::SetConfiguration");
420
421 ResTable_config configuration;
422 memset(&configuration, 0, sizeof(configuration));
423 configuration.mcc = static_cast<uint16_t>(mcc);
424 configuration.mnc = static_cast<uint16_t>(mnc);
425 configuration.orientation = static_cast<uint8_t>(orientation);
426 configuration.touchscreen = static_cast<uint8_t>(touchscreen);
427 configuration.density = static_cast<uint16_t>(density);
428 configuration.keyboard = static_cast<uint8_t>(keyboard);
429 configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
430 configuration.navigation = static_cast<uint8_t>(navigation);
431 configuration.screenWidth = static_cast<uint16_t>(screen_width);
432 configuration.screenHeight = static_cast<uint16_t>(screen_height);
433 configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
434 configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
435 configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
436 configuration.screenLayout = static_cast<uint8_t>(screen_layout);
437 configuration.uiMode = static_cast<uint8_t>(ui_mode);
438 configuration.colorMode = static_cast<uint8_t>(color_mode);
439 configuration.sdkVersion = static_cast<uint16_t>(major_version);
440
441 if (locale != nullptr) {
442 ScopedUtfChars locale_utf8(env, locale);
443 CHECK(locale_utf8.c_str() != nullptr);
444 configuration.setBcp47Locale(locale_utf8.c_str());
445 }
446
447 // Constants duplicated from Java class android.content.res.Configuration.
448 static const jint kScreenLayoutRoundMask = 0x300;
449 static const jint kScreenLayoutRoundShift = 8;
450
451 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
452 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
453 // into screenLayout2.
454 configuration.screenLayout2 =
455 static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
456
457 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
458 assetmanager->SetConfiguration(configuration);
459}
460
461static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
462 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
463
464 jobject sparse_array =
465 env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
466
467 if (sparse_array == nullptr) {
468 // An exception is pending.
469 return nullptr;
470 }
471
472 assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
473 jstring jpackage_name = env->NewStringUTF(package_name.c_str());
474 if (jpackage_name == nullptr) {
475 // An exception is pending.
476 return;
477 }
478
479 env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
480 jpackage_name);
481 });
482 return sparse_array;
483}
484
485static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
486 ScopedUtfChars path_utf8(env, path);
487 if (path_utf8.c_str() == nullptr) {
488 // This will throw NPE.
489 return nullptr;
490 }
491
492 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
493 std::unique_ptr<AssetDir> asset_dir =
494 assetmanager->OpenDir(path_utf8.c_str());
495 if (asset_dir == nullptr) {
496 jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
497 return nullptr;
498 }
499
500 const size_t file_count = asset_dir->getFileCount();
501
502 jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
503 if (array == nullptr) {
504 return nullptr;
505 }
506
507 for (size_t i = 0; i < file_count; i++) {
508 jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
509
510 // Check for errors creating the strings (if malformed or no memory).
511 if (env->ExceptionCheck()) {
512 return nullptr;
513 }
514
515 env->SetObjectArrayElement(array, i, java_string);
516
517 // If we have a large amount of string in our array, we might overflow the
518 // local reference table of the VM.
519 env->DeleteLocalRef(java_string);
520 }
521 return array;
522}
523
524static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
525 jint access_mode) {
526 ScopedUtfChars asset_path_utf8(env, asset_path);
527 if (asset_path_utf8.c_str() == nullptr) {
528 // This will throw NPE.
529 return 0;
530 }
531
532 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
533
534 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
535 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
536 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
537 return 0;
538 }
539
540 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
541 std::unique_ptr<Asset> asset =
542 assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
543 if (!asset) {
544 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
545 return 0;
546 }
547 return reinterpret_cast<jlong>(asset.release());
548}
549
550static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
551 jlongArray out_offsets) {
552 ScopedUtfChars asset_path_utf8(env, asset_path);
553 if (asset_path_utf8.c_str() == nullptr) {
554 // This will throw NPE.
555 return nullptr;
556 }
557
558 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
559
560 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
561 std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
562 if (!asset) {
563 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
564 return nullptr;
565 }
566 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
567}
568
569static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
570 jstring asset_path, jint access_mode) {
571 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
572 ScopedUtfChars asset_path_utf8(env, asset_path);
573 if (asset_path_utf8.c_str() == nullptr) {
574 // This will throw NPE.
575 return 0;
576 }
577
578 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
579
580 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
581 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
582 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
583 return 0;
584 }
585
586 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
587 std::unique_ptr<Asset> asset;
588 if (cookie != kInvalidCookie) {
589 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
590 static_cast<Asset::AccessMode>(access_mode));
591 } else {
592 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
593 static_cast<Asset::AccessMode>(access_mode));
594 }
595
596 if (!asset) {
597 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
598 return 0;
599 }
600 return reinterpret_cast<jlong>(asset.release());
601}
602
603static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
604 jstring asset_path, jlongArray out_offsets) {
605 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
606 ScopedUtfChars asset_path_utf8(env, asset_path);
607 if (asset_path_utf8.c_str() == nullptr) {
608 // This will throw NPE.
609 return nullptr;
610 }
611
612 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
613
614 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
615 std::unique_ptr<Asset> asset;
616 if (cookie != kInvalidCookie) {
617 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
618 } else {
619 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
620 }
621
622 if (!asset) {
623 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
624 return nullptr;
625 }
626 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
627}
628
629static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
630 jstring asset_path) {
631 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
632 ScopedUtfChars asset_path_utf8(env, asset_path);
633 if (asset_path_utf8.c_str() == nullptr) {
634 // This will throw NPE.
635 return 0;
636 }
637
638 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
639
640 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
641 std::unique_ptr<Asset> asset;
642 if (cookie != kInvalidCookie) {
643 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
644 } else {
645 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
646 }
647
648 if (!asset) {
649 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
650 return 0;
651 }
652
653 // May be nullptr.
654 const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
655
656 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
657 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
658 asset.reset();
659
660 if (err != NO_ERROR) {
661 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
662 return 0;
663 }
664 return reinterpret_cast<jlong>(xml_tree.release());
665}
666
667static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
668 jshort density, jobject typed_value,
669 jboolean resolve_references) {
670 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
671 Res_value value;
672 ResTable_config selected_config;
673 uint32_t flags;
674 ApkAssetsCookie cookie =
675 assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
676 static_cast<uint16_t>(density), &value, &selected_config, &flags);
677 if (cookie == kInvalidCookie) {
678 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
679 }
680
681 uint32_t ref = static_cast<uint32_t>(resid);
682 if (resolve_references) {
683 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
684 if (cookie == kInvalidCookie) {
685 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
686 }
687 }
688 return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
689}
690
691static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
692 jint bag_entry_id, jobject typed_value) {
693 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
694 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
695 if (bag == nullptr) {
696 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
697 }
698
699 uint32_t type_spec_flags = bag->type_spec_flags;
700 ApkAssetsCookie cookie = kInvalidCookie;
701 const Res_value* bag_value = nullptr;
702 for (const ResolvedBag::Entry& entry : bag) {
703 if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
704 cookie = entry.cookie;
705 bag_value = &entry.value;
706
707 // Keep searching (the old implementation did that).
708 }
709 }
710
711 if (cookie == kInvalidCookie) {
712 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
713 }
714
715 Res_value value = *bag_value;
716 uint32_t ref = static_cast<uint32_t>(resid);
717 ResTable_config selected_config;
718 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
719 if (cookie == kInvalidCookie) {
720 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
721 }
722 return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
723}
724
725static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
726 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
727 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
728 if (bag == nullptr) {
729 return nullptr;
730 }
731
732 jintArray array = env->NewIntArray(bag->entry_count);
733 if (env->ExceptionCheck()) {
734 return nullptr;
735 }
736
737 for (uint32_t i = 0; i < bag->entry_count; i++) {
738 jint attr_resid = bag->entries[i].key;
739 env->SetIntArrayRegion(array, i, 1, &attr_resid);
740 }
741 return array;
742}
743
744static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
745 jint resid) {
746 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
747 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
748 if (bag == nullptr) {
749 return nullptr;
750 }
751
752 jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
753 if (array == nullptr) {
754 return nullptr;
755 }
756
757 for (uint32_t i = 0; i < bag->entry_count; i++) {
758 const ResolvedBag::Entry& entry = bag->entries[i];
759
760 // Resolve any references to their final value.
761 Res_value value = entry.value;
762 ResTable_config selected_config;
763 uint32_t flags;
764 uint32_t ref;
765 ApkAssetsCookie cookie =
766 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
767 if (cookie == kInvalidCookie) {
768 return nullptr;
769 }
770
771 if (value.dataType == Res_value::TYPE_STRING) {
772 const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
773 const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
774
775 jstring java_string = nullptr;
776 size_t str_len;
777 const char* str_utf8 = pool->string8At(value.data, &str_len);
778 if (str_utf8 != nullptr) {
779 java_string = env->NewStringUTF(str_utf8);
780 } else {
781 const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
782 java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
783 }
784
785 // Check for errors creating the strings (if malformed or no memory).
786 if (env->ExceptionCheck()) {
787 return nullptr;
788 }
789
790 env->SetObjectArrayElement(array, i, java_string);
791
792 // If we have a large amount of string in our array, we might overflow the
793 // local reference table of the VM.
794 env->DeleteLocalRef(java_string);
795 }
796 }
797 return array;
798}
799
800static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
801 jint resid) {
802 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
803 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
804 if (bag == nullptr) {
805 return nullptr;
806 }
807
808 jintArray array = env->NewIntArray(bag->entry_count * 2);
809 if (array == nullptr) {
810 return nullptr;
811 }
812
813 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
814 if (buffer == nullptr) {
815 return nullptr;
816 }
817
818 for (size_t i = 0; i < bag->entry_count; i++) {
819 const ResolvedBag::Entry& entry = bag->entries[i];
820 Res_value value = entry.value;
821 ResTable_config selected_config;
822 uint32_t flags;
823 uint32_t ref;
824 ApkAssetsCookie cookie =
825 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
826 if (cookie == kInvalidCookie) {
827 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
828 return nullptr;
829 }
830
831 jint string_index = -1;
832 if (value.dataType == Res_value::TYPE_STRING) {
833 string_index = static_cast<jint>(value.data);
834 }
835
836 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
837 buffer[(i * 2) + 1] = string_index;
838 }
839 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
840 return array;
841}
842
843static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
844 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
845 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
846 if (bag == nullptr) {
847 return nullptr;
848 }
849
850 jintArray array = env->NewIntArray(bag->entry_count);
851 if (array == nullptr) {
852 return nullptr;
853 }
854
855 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
856 if (buffer == nullptr) {
857 return nullptr;
858 }
859
860 for (size_t i = 0; i < bag->entry_count; i++) {
861 const ResolvedBag::Entry& entry = bag->entries[i];
862 Res_value value = entry.value;
863 ResTable_config selected_config;
864 uint32_t flags;
865 uint32_t ref;
866 ApkAssetsCookie cookie =
867 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
868 if (cookie == kInvalidCookie) {
869 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
870 return nullptr;
871 }
872
873 if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
874 buffer[i] = static_cast<jint>(value.data);
875 }
876 }
877 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
878 return array;
879}
880
881static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
882 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
883 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
884 if (bag == nullptr) {
885 return -1;
886 }
887 return static_cast<jint>(bag->entry_count);
888}
889
890static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
891 jintArray out_data) {
892 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
893 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
894 if (bag == nullptr) {
895 return -1;
896 }
897
898 const jsize out_data_length = env->GetArrayLength(out_data);
899 if (env->ExceptionCheck()) {
900 return -1;
901 }
902
903 if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
904 jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
905 return -1;
906 }
907
908 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
909 if (buffer == nullptr) {
910 return -1;
911 }
912
913 jint* cursor = buffer;
914 for (size_t i = 0; i < bag->entry_count; i++) {
915 const ResolvedBag::Entry& entry = bag->entries[i];
916 Res_value value = entry.value;
917 ResTable_config selected_config;
918 selected_config.density = 0;
919 uint32_t flags = bag->type_spec_flags;
Todd Kennedy1d63cc32018-04-18 10:25:45 -0700920 uint32_t ref = 0;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800921 ApkAssetsCookie cookie =
922 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
923 if (cookie == kInvalidCookie) {
924 env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
925 return -1;
926 }
927
928 // Deal with the special @null value -- it turns back to TYPE_NULL.
929 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
930 value.dataType = Res_value::TYPE_NULL;
931 value.data = Res_value::DATA_NULL_UNDEFINED;
932 }
933
934 cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
935 cursor[STYLE_DATA] = static_cast<jint>(value.data);
936 cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
937 cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
938 cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
939 cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
940 cursor += STYLE_NUM_ENTRIES;
941 }
942 env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
943 return static_cast<jint>(bag->entry_count);
944}
945
946static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
947 jstring def_type, jstring def_package) {
948 ScopedUtfChars name_utf8(env, name);
949 if (name_utf8.c_str() == nullptr) {
950 // This will throw NPE.
951 return 0;
952 }
953
954 std::string type;
955 if (def_type != nullptr) {
956 ScopedUtfChars type_utf8(env, def_type);
957 CHECK(type_utf8.c_str() != nullptr);
958 type = type_utf8.c_str();
959 }
960
961 std::string package;
962 if (def_package != nullptr) {
963 ScopedUtfChars package_utf8(env, def_package);
964 CHECK(package_utf8.c_str() != nullptr);
965 package = package_utf8.c_str();
966 }
967 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
968 return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
969}
970
971static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
972 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
973 AssetManager2::ResourceName name;
974 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
975 return nullptr;
976 }
977
978 std::string result;
979 if (name.package != nullptr) {
980 result.append(name.package, name.package_len);
981 }
982
983 if (name.type != nullptr || name.type16 != nullptr) {
984 if (!result.empty()) {
985 result += ":";
986 }
987
988 if (name.type != nullptr) {
989 result.append(name.type, name.type_len);
990 } else {
991 result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
992 }
993 }
994
995 if (name.entry != nullptr || name.entry16 != nullptr) {
996 if (!result.empty()) {
997 result += "/";
998 }
999
1000 if (name.entry != nullptr) {
1001 result.append(name.entry, name.entry_len);
1002 } else {
1003 result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
1004 }
1005 }
1006 return env->NewStringUTF(result.c_str());
1007}
1008
1009static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1010 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1011 AssetManager2::ResourceName name;
1012 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1013 return nullptr;
1014 }
1015
1016 if (name.package != nullptr) {
1017 return env->NewStringUTF(name.package);
1018 }
1019 return nullptr;
1020}
1021
1022static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1023 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1024 AssetManager2::ResourceName name;
1025 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1026 return nullptr;
1027 }
1028
1029 if (name.type != nullptr) {
1030 return env->NewStringUTF(name.type);
1031 } else if (name.type16 != nullptr) {
1032 return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
1033 }
1034 return nullptr;
1035}
1036
1037static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1038 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1039 AssetManager2::ResourceName name;
1040 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1041 return nullptr;
1042 }
1043
1044 if (name.entry != nullptr) {
1045 return env->NewStringUTF(name.entry);
1046 } else if (name.entry16 != nullptr) {
1047 return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
1048 }
1049 return nullptr;
1050}
1051
1052static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
1053 jboolean exclude_system) {
1054 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1055 std::set<std::string> locales =
1056 assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
1057
1058 jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
1059 if (array == nullptr) {
1060 return nullptr;
1061 }
1062
1063 size_t idx = 0;
1064 for (const std::string& locale : locales) {
1065 jstring java_string = env->NewStringUTF(locale.c_str());
1066 if (java_string == nullptr) {
1067 return nullptr;
1068 }
1069 env->SetObjectArrayElement(array, idx++, java_string);
1070 env->DeleteLocalRef(java_string);
1071 }
1072 return array;
1073}
1074
1075static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
1076 jobject result =
1077 env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1078 if (result == nullptr) {
1079 return nullptr;
1080 }
1081
1082 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1083 config.smallestScreenWidthDp);
1084 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1085 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1086 return result;
1087}
1088
1089static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1090 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1091 std::set<ResTable_config> configurations =
1092 assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1093
1094 jobjectArray array =
1095 env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1096 if (array == nullptr) {
1097 return nullptr;
1098 }
1099
1100 size_t idx = 0;
1101 for (const ResTable_config& configuration : configurations) {
1102 jobject java_configuration = ConstructConfigurationObject(env, configuration);
1103 if (java_configuration == nullptr) {
1104 return nullptr;
1105 }
1106
1107 env->SetObjectArrayElement(array, idx++, java_configuration);
1108 env->DeleteLocalRef(java_configuration);
1109 }
1110 return array;
1111}
1112
1113static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1114 jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1115 jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
1116 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1117 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1118 CHECK(theme->GetAssetManager() == &(*assetmanager));
1119 (void) assetmanager;
1120
1121 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1122 uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
1123 uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
1124
1125 jsize attrs_len = env->GetArrayLength(java_attrs);
1126 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1127 if (attrs == nullptr) {
1128 return;
1129 }
1130
1131 ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
1132 static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
1133 out_values, out_indices);
1134 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1135}
1136
1137static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1138 jint def_style_attr, jint def_style_resid, jintArray java_values,
1139 jintArray java_attrs, jintArray out_java_values,
1140 jintArray out_java_indices) {
1141 const jsize attrs_len = env->GetArrayLength(java_attrs);
1142 const jsize out_values_len = env->GetArrayLength(out_java_values);
1143 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1144 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1145 return JNI_FALSE;
1146 }
1147
1148 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1149 if (attrs == nullptr) {
1150 return JNI_FALSE;
1151 }
1152
1153 jint* values = nullptr;
1154 jsize values_len = 0;
1155 if (java_values != nullptr) {
1156 values_len = env->GetArrayLength(java_values);
1157 values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
1158 if (values == nullptr) {
1159 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1160 return JNI_FALSE;
1161 }
1162 }
1163
1164 jint* out_values =
1165 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1166 if (out_values == nullptr) {
1167 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1168 if (values != nullptr) {
1169 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1170 }
1171 return JNI_FALSE;
1172 }
1173
1174 jint* out_indices = nullptr;
1175 if (out_java_indices != nullptr) {
1176 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1177 if (out_indices_len > attrs_len) {
1178 out_indices =
1179 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1180 if (out_indices == nullptr) {
1181 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1182 if (values != nullptr) {
1183 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1184 }
1185 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1186 return JNI_FALSE;
1187 }
1188 }
1189 }
1190
1191 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1192 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1193 CHECK(theme->GetAssetManager() == &(*assetmanager));
1194 (void) assetmanager;
1195
1196 bool result = ResolveAttrs(
1197 theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1198 reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1199 attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1200 if (out_indices != nullptr) {
1201 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1202 }
1203
1204 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1205 if (values != nullptr) {
1206 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1207 }
1208 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1209 return result ? JNI_TRUE : JNI_FALSE;
1210}
1211
1212static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1213 jlong xml_parser_ptr, jintArray java_attrs,
1214 jintArray out_java_values, jintArray out_java_indices) {
1215 const jsize attrs_len = env->GetArrayLength(java_attrs);
1216 const jsize out_values_len = env->GetArrayLength(out_java_values);
1217 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1218 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1219 return JNI_FALSE;
1220 }
1221
1222 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1223 if (attrs == nullptr) {
1224 return JNI_FALSE;
1225 }
1226
1227 jint* out_values =
1228 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1229 if (out_values == nullptr) {
1230 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1231 return JNI_FALSE;
1232 }
1233
1234 jint* out_indices = nullptr;
1235 if (out_java_indices != nullptr) {
1236 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1237 if (out_indices_len > attrs_len) {
1238 out_indices =
1239 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1240 if (out_indices == nullptr) {
1241 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1242 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1243 return JNI_FALSE;
1244 }
1245 }
1246 }
1247
1248 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1249 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1250
1251 bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1252 reinterpret_cast<uint32_t*>(attrs), attrs_len,
1253 reinterpret_cast<uint32_t*>(out_values),
1254 reinterpret_cast<uint32_t*>(out_indices));
1255
1256 if (out_indices != nullptr) {
1257 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1258 }
1259 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1260 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1261 return result ? JNI_TRUE : JNI_FALSE;
1262}
1263
1264static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1265 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1266 return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1267}
1268
1269static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1270 delete reinterpret_cast<Theme*>(theme_ptr);
1271}
1272
1273static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1274 jint resid, jboolean force) {
1275 // AssetManager is accessed via the theme, so grab an explicit lock here.
1276 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1277 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1278 CHECK(theme->GetAssetManager() == &(*assetmanager));
1279 (void) assetmanager;
1280 theme->ApplyStyle(static_cast<uint32_t>(resid), force);
1281
1282 // TODO(adamlesinski): Consider surfacing exception when result is failure.
1283 // CTS currently expects no exceptions from this method.
1284 // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1285 // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
1286}
1287
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001288static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1289 jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001290 Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1291 Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001292
1293 if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1294 ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
1295 CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
1296 (void) dst_assetmanager;
1297
1298 ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
1299 CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
1300 (void) src_assetmanager;
1301
1302 dst_theme->SetTo(*src_theme);
1303 } else {
1304 dst_theme->SetTo(*src_theme);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001305 }
1306}
1307
1308static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1309 reinterpret_cast<Theme*>(theme_ptr)->Clear();
1310}
1311
1312static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1313 jint resid, jobject typed_value,
1314 jboolean resolve_references) {
1315 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1316 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1317 CHECK(theme->GetAssetManager() == &(*assetmanager));
1318 (void) assetmanager;
1319
1320 Res_value value;
1321 uint32_t flags;
1322 ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1323 if (cookie == kInvalidCookie) {
1324 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1325 }
1326
1327 uint32_t ref = 0u;
1328 if (resolve_references) {
1329 ResTable_config selected_config;
1330 cookie =
1331 theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1332 if (cookie == kInvalidCookie) {
1333 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1334 }
1335 }
1336 return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1337}
1338
1339static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1340 jint priority, jstring tag, jstring prefix) {
1341 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1342 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1343 CHECK(theme->GetAssetManager() == &(*assetmanager));
1344 (void) assetmanager;
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001345 (void) priority;
1346 (void) tag;
1347 (void) prefix;
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001348
1349 theme->Dump();
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001350}
1351
1352static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1353 jlong theme_ptr) {
1354 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1355 return static_cast<jint>(theme->GetChangingConfigurations());
1356}
1357
1358static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1359 delete reinterpret_cast<Asset*>(asset_ptr);
1360}
1361
1362static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1363 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1364 uint8_t b;
1365 ssize_t res = asset->read(&b, sizeof(b));
1366 return res == sizeof(b) ? static_cast<jint>(b) : -1;
1367}
1368
1369static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1370 jint offset, jint len) {
1371 if (len == 0) {
1372 return 0;
1373 }
1374
1375 jsize buffer_len = env->GetArrayLength(java_buffer);
1376 if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1377 offset > buffer_len - len) {
1378 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1379 return -1;
1380 }
1381
1382 ScopedByteArrayRW byte_array(env, java_buffer);
1383 if (byte_array.get() == nullptr) {
1384 return -1;
1385 }
1386
1387 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1388 ssize_t res = asset->read(byte_array.get() + offset, len);
1389 if (res < 0) {
1390 jniThrowException(env, "java/io/IOException", "");
1391 return -1;
1392 }
1393 return res > 0 ? static_cast<jint>(res) : -1;
1394}
1395
1396static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1397 jint whence) {
1398 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1399 return static_cast<jlong>(asset->seek(
1400 static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1401}
1402
1403static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1404 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1405 return static_cast<jlong>(asset->getLength());
1406}
1407
1408static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1409 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1410 return static_cast<jlong>(asset->getRemainingLength());
1411}
1412
1413// ----------------------------------------------------------------------------
1414
1415// JNI registration.
1416static const JNINativeMethod gAssetManagerMethods[] = {
1417 // AssetManager setup methods.
1418 {"nativeCreate", "()J", (void*)NativeCreate},
1419 {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1420 {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1421 {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1422 (void*)NativeSetConfiguration},
1423 {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
1424 (void*)NativeGetAssignedPackageIdentifiers},
1425
1426 // AssetManager file methods.
1427 {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1428 {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1429 {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1430 (void*)NativeOpenAssetFd},
1431 {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1432 {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1433 (void*)NativeOpenNonAssetFd},
1434 {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
1435
1436 // AssetManager resource methods.
1437 {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1438 {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1439 (void*)NativeGetResourceBagValue},
1440 {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1441 {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1442 (void*)NativeGetResourceStringArray},
1443 {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1444 {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1445 {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1446 {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1447
1448 // AssetManager resource name/ID methods.
1449 {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1450 (void*)NativeGetResourceIdentifier},
1451 {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1452 {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1453 {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1454 {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
1455 {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1456 {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1457 (void*)NativeGetSizeConfigurations},
1458
1459 // Style attribute related methods.
1460 {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1461 {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1462 {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1463
1464 // Theme related methods.
1465 {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1466 {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1467 {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001468 {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001469 {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1470 {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1471 (void*)NativeThemeGetAttributeValue},
1472 {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1473 {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1474
1475 // AssetInputStream methods.
1476 {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1477 {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1478 {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1479 {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1480 {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1481 {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1482
1483 // System/idmap related methods.
1484 {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
Mårten Kongstad06a1ac82018-09-20 13:09:47 +02001485 {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
1486 (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001487
1488 // Global management/debug methods.
1489 {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1490 {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1491 {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1492};
1493
1494int register_android_content_AssetManager(JNIEnv* env) {
1495 jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1496 gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1497
1498 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1499 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1500 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1501 gTypedValueOffsets.mString =
1502 GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1503 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1504 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1505 gTypedValueOffsets.mChangingConfigurations =
1506 GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1507 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1508
1509 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1510 gAssetFileDescriptorOffsets.mFd =
1511 GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1512 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1513 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1514
1515 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1516 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1517
1518 jclass stringClass = FindClassOrDie(env, "java/lang/String");
1519 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1520
1521 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1522 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1523 gSparseArrayOffsets.constructor =
1524 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1525 gSparseArrayOffsets.put =
1526 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1527
1528 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1529 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1530 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1531 gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1532 GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1533 gConfigurationOffsets.mScreenWidthDpOffset =
1534 GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1535 gConfigurationOffsets.mScreenHeightDpOffset =
1536 GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1537
1538 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1539 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540}
1541
1542}; // namespace android