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