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