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