blob: 062b886f54a17e9512866eb2fd6cef375658fca2 [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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <stdio.h>
Adam Lesinskibde1df22018-02-09 11:12:22 -080022#include <sys/stat.h>
Adam Lesinskibebfcc42018-02-12 14:27:46 -080023#include <sys/types.h>
24#include <sys/wait.h>
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020025#include <unistd.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010026
Dan Albert46d84442014-11-18 16:07:51 -080027#include <private/android_filesystem_config.h> // for AID_SYSTEM
28
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020029#include <sstream>
30#include <string>
31
Adam Lesinskibebfcc42018-02-12 14:27:46 -080032#include "android-base/logging.h"
33#include "android-base/properties.h"
34#include "android-base/stringprintf.h"
35#include "android_runtime/android_util_AssetManager.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080036#include "android_runtime/AndroidRuntime.h"
37#include "android_util_Binder.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080038#include "androidfw/Asset.h"
39#include "androidfw/AssetManager.h"
40#include "androidfw/AssetManager2.h"
41#include "androidfw/AttributeResolution.h"
42#include "androidfw/MutexGuard.h"
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020043#include "androidfw/PosixUtils.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080044#include "androidfw/ResourceTypes.h"
Winson2f3669b2019-01-11 11:28:34 -080045#include "androidfw/ResourceUtils.h"
46
Dan Albert3a091b72014-11-20 15:41:25 -080047#include "core_jni_helpers.h"
48#include "jni.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080049#include "nativehelper/JNIHelp.h"
50#include "nativehelper/ScopedPrimitiveArray.h"
51#include "nativehelper/ScopedStringChars.h"
52#include "nativehelper/ScopedUtfChars.h"
Dan Albert46d84442014-11-18 16:07:51 -080053#include "utils/Log.h"
Adam Lesinski11875902017-01-23 12:58:11 -080054#include "utils/misc.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080055#include "utils/String8.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080056#include "utils/Trace.h"
Dan Albert46d84442014-11-18 16:07:51 -080057
Mårten Kongstad48d22322014-01-31 14:43:27 +010058extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
59extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
60
Adam Lesinskibebfcc42018-02-12 14:27:46 -080061using ::android::base::StringPrintf;
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020062using ::android::util::ExecuteBinary;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64namespace android {
65
66// ----------------------------------------------------------------------------
67
Adam Lesinskibebfcc42018-02-12 14:27:46 -080068static struct typedvalue_offsets_t {
69 jfieldID mType;
70 jfieldID mData;
71 jfieldID mString;
72 jfieldID mAssetCookie;
73 jfieldID mResourceId;
74 jfieldID mChangingConfigurations;
75 jfieldID mDensity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076} gTypedValueOffsets;
77
Adam Lesinskibebfcc42018-02-12 14:27:46 -080078static struct assetfiledescriptor_offsets_t {
79 jfieldID mFd;
80 jfieldID mStartOffset;
81 jfieldID mLength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082} gAssetFileDescriptorOffsets;
83
Nicolas Geoffraya55a59a2018-05-10 15:00:13 +010084// This is also used by asset_manager.cpp.
85assetmanager_offsets_t gAssetManagerOffsets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Adam Lesinskibebfcc42018-02-12 14:27:46 -080087static struct {
88 jfieldID native_ptr;
89} gApkAssetsFields;
90
91static struct sparsearray_offsets_t {
92 jclass classObject;
93 jmethodID constructor;
94 jmethodID put;
Adam Lesinskide898ff2014-01-29 18:20:45 -080095} gSparseArrayOffsets;
96
Adam Lesinskibebfcc42018-02-12 14:27:46 -080097static struct configuration_offsets_t {
98 jclass classObject;
99 jmethodID constructor;
100 jfieldID mSmallestScreenWidthDpOffset;
101 jfieldID mScreenWidthDpOffset;
102 jfieldID mScreenHeightDpOffset;
Filip Gruszczynski23493322015-07-29 17:02:59 -0700103} gConfigurationOffsets;
104
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100105static struct arraymap_offsets_t {
106 jclass classObject;
107 jmethodID constructor;
108 jmethodID put;
109} gArrayMapOffsets;
110
Wei Wangd41a9612019-10-10 11:34:13 -0700111static jclass g_stringClass = nullptr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
113// ----------------------------------------------------------------------------
114
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800115// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
116constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
117 return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
118}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800120constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
121 return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122}
123
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200124static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
125 jclass /*clazz*/) {
126 // --input-directory can be given multiple times, but idmap2 expects the directory to exist
127 std::vector<std::string> input_dirs;
128 struct stat st;
129 if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
130 input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
131 }
132
133 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
134 input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
135 }
136
Jeongik Chacba95792019-07-09 23:58:01 +0900137 if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
138 input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR);
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200139 }
140
Mårten Kongstad48c24cf2019-02-25 10:54:09 +0100141 if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
142 input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR);
143 }
144
Mårten Kongstadeb8a5c02019-02-25 14:18:17 +0100145 if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) {
146 input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR);
147 }
148
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200149 if (input_dirs.empty()) {
150 LOG(WARNING) << "no directories for idmap2 to scan";
151 return env->NewObjectArray(0, g_stringClass, nullptr);
152 }
153
Yabin Cuia60dc9e2019-02-26 16:12:46 -0800154 if (access("/system/bin/idmap2", X_OK) == -1) {
155 PLOG(WARNING) << "unable to execute idmap2";
156 return nullptr;
157 }
158
Mårten Kongstad06a1ac82018-09-20 13:09:47 +0200159 std::vector<std::string> argv{"/system/bin/idmap2",
160 "scan",
161 "--recursive",
162 "--target-package-name", "android",
163 "--target-apk-path", "/system/framework/framework-res.apk",
164 "--output-directory", "/data/resource-cache"};
165
166 for (const auto& dir : input_dirs) {
167 argv.push_back("--input-directory");
168 argv.push_back(dir);
169 }
170
171 const auto result = ExecuteBinary(argv);
172
173 if (!result) {
174 LOG(ERROR) << "failed to execute idmap2";
175 return nullptr;
176 }
177
178 if (result->status != 0) {
179 LOG(ERROR) << "idmap2: " << result->stderr;
180 return nullptr;
181 }
182
183 std::vector<std::string> idmap_paths;
184 std::istringstream input(result->stdout);
185 std::string path;
186 while (std::getline(input, path)) {
187 idmap_paths.push_back(path);
188 }
189
190 jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
191 if (array == nullptr) {
192 return nullptr;
193 }
194 for (size_t i = 0; i < idmap_paths.size(); i++) {
195 const std::string path = idmap_paths[i];
196 jstring java_string = env->NewStringUTF(path.c_str());
197 if (env->ExceptionCheck()) {
198 return nullptr;
199 }
200 env->SetObjectArrayElement(array, i, java_string);
201 env->DeleteLocalRef(java_string);
202 }
203 return array;
204}
205
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800206static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
207 uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
208 env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
209 env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
210 ApkAssetsCookieToJavaCookie(cookie));
211 env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
212 env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
213 env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
214 env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
215 if (config != nullptr) {
216 env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
217 }
218 return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
Adam Lesinski11875902017-01-23 12:58:11 -0800219}
220
221// ----------------------------------------------------------------------------
222
Ryan Mitchellfe50d732019-12-19 16:12:35 -0800223static std::unique_ptr<DynamicLibManager> sDynamicLibManager =
224 std::make_unique<DynamicLibManager>();
225
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800226// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
227struct GuardedAssetManager : public ::AAssetManager {
Ryan Mitchellfe50d732019-12-19 16:12:35 -0800228 GuardedAssetManager() : guarded_assetmanager(sDynamicLibManager.get()) {}
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800229 Guarded<AssetManager2> guarded_assetmanager;
Adam Lesinski11875902017-01-23 12:58:11 -0800230};
231
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800232::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
233 jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
234 ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
235 if (am == nullptr) {
236 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
237 return nullptr;
238 }
239 return am;
240}
Adam Lesinski11875902017-01-23 12:58:11 -0800241
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800242Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
243 if (assetmanager == nullptr) {
244 return nullptr;
245 }
246 return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
247}
Adam Lesinski11875902017-01-23 12:58:11 -0800248
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800249Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
250 return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
251}
Adam Lesinski11875902017-01-23 12:58:11 -0800252
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800253static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
254 return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
255}
Adam Lesinski11875902017-01-23 12:58:11 -0800256
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100257static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
Ryan Mitchell2e394222019-08-28 12:10:51 -0700258 jstring package_name) {
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100259 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
260 const ScopedUtfChars package_name_utf8(env, package_name);
261 CHECK(package_name_utf8.c_str() != nullptr);
262 const std::string std_package_name(package_name_utf8.c_str());
263 const std::unordered_map<std::string, std::string>* map = nullptr;
264
265 assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
266 if (this_package_name == std_package_name) {
267 map = assetmanager->GetOverlayableMapForPackage(package_id);
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800268 return false;
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100269 }
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800270 return true;
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +0100271 });
272
273 if (map == nullptr) {
274 return nullptr;
275 }
276
277 jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor);
278 if (array_map == nullptr) {
279 return nullptr;
280 }
281
282 for (const auto& iter : *map) {
283 jstring name = env->NewStringUTF(iter.first.c_str());
284 if (env->ExceptionCheck()) {
285 return nullptr;
286 }
287
288 jstring actor = env->NewStringUTF(iter.second.c_str());
289 if (env->ExceptionCheck()) {
290 env->DeleteLocalRef(name);
291 return nullptr;
292 }
293
294 env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor);
295
296 env->DeleteLocalRef(name);
297 env->DeleteLocalRef(actor);
298 }
299
300 return array_map;
301}
302
Ryan Mitchell2e394222019-08-28 12:10:51 -0700303static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlong ptr,
304 jstring package_name) {
305 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
306 const ScopedUtfChars package_name_utf8(env, package_name);
307 CHECK(package_name_utf8.c_str() != nullptr);
308 const std::string std_package_name(package_name_utf8.c_str());
309
310 std::string result;
311 if (!assetmanager->GetOverlayablesToString(std_package_name, &result)) {
312 return nullptr;
313 }
314
315 return env->NewStringUTF(result.c_str());
316}
317
Brett Chabot15c7bcd2019-06-19 10:19:00 -0700318#ifdef __ANDROID__ // Layoutlib does not support parcel
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800319static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
320 jlongArray out_offsets) {
321 off64_t start_offset, length;
322 int fd = asset->openFileDescriptor(&start_offset, &length);
323 asset.reset();
Adam Lesinski11875902017-01-23 12:58:11 -0800324
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800325 if (fd < 0) {
326 jniThrowException(env, "java/io/FileNotFoundException",
327 "This file can not be opened as a file descriptor; it is probably "
328 "compressed");
329 return nullptr;
330 }
Adam Lesinski11875902017-01-23 12:58:11 -0800331
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800332 jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
333 if (offsets == nullptr) {
334 close(fd);
335 return nullptr;
336 }
337
338 offsets[0] = start_offset;
339 offsets[1] = length;
340
341 env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
342
343 jobject file_desc = jniCreateFileDescriptor(env, fd);
344 if (file_desc == nullptr) {
345 close(fd);
346 return nullptr;
347 }
348 return newParcelFileDescriptor(env, file_desc);
349}
Brett Chabot15c7bcd2019-06-19 10:19:00 -0700350#else
351static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
352 jlongArray out_offsets) {
353 jniThrowException(env, "java/lang/UnsupportedOperationException",
354 "Implement me");
355 // never reached
356 return nullptr;
357}
358#endif
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800359
360static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
361 return Asset::getGlobalCount();
362}
363
364static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
365 String8 alloc = Asset::getAssetAllocations();
366 if (alloc.length() <= 0) {
367 return nullptr;
368 }
369 return env->NewStringUTF(alloc.string());
370}
371
372static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
373 // TODO(adamlesinski): Switch to AssetManager2.
374 return AssetManager::getGlobalCount();
375}
376
377static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
378 // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
379 // AssetManager2 in a contiguous block (GuardedAssetManager).
380 return reinterpret_cast<jlong>(new GuardedAssetManager());
381}
382
383static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
384 delete reinterpret_cast<GuardedAssetManager*>(ptr);
385}
386
387static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
388 jobjectArray apk_assets_array, jboolean invalidate_caches) {
389 ATRACE_NAME("AssetManager::SetApkAssets");
390
391 const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
392 std::vector<const ApkAssets*> apk_assets;
393 apk_assets.reserve(apk_assets_len);
394 for (jsize i = 0; i < apk_assets_len; i++) {
395 jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
396 if (obj == nullptr) {
397 std::string msg = StringPrintf("ApkAssets at index %d is null", i);
398 jniThrowNullPointerException(env, msg.c_str());
399 return;
400 }
401
402 jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
403 if (env->ExceptionCheck()) {
404 return;
405 }
406 apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
407 }
408
409 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
410 assetmanager->SetApkAssets(apk_assets, invalidate_caches);
411}
412
413static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
414 jstring locale, jint orientation, jint touchscreen, jint density,
415 jint keyboard, jint keyboard_hidden, jint navigation,
416 jint screen_width, jint screen_height,
417 jint smallest_screen_width_dp, jint screen_width_dp,
418 jint screen_height_dp, jint screen_layout, jint ui_mode,
419 jint color_mode, jint major_version) {
420 ATRACE_NAME("AssetManager::SetConfiguration");
421
422 ResTable_config configuration;
423 memset(&configuration, 0, sizeof(configuration));
424 configuration.mcc = static_cast<uint16_t>(mcc);
425 configuration.mnc = static_cast<uint16_t>(mnc);
426 configuration.orientation = static_cast<uint8_t>(orientation);
427 configuration.touchscreen = static_cast<uint8_t>(touchscreen);
428 configuration.density = static_cast<uint16_t>(density);
429 configuration.keyboard = static_cast<uint8_t>(keyboard);
430 configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
431 configuration.navigation = static_cast<uint8_t>(navigation);
432 configuration.screenWidth = static_cast<uint16_t>(screen_width);
433 configuration.screenHeight = static_cast<uint16_t>(screen_height);
434 configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
435 configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
436 configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
437 configuration.screenLayout = static_cast<uint8_t>(screen_layout);
438 configuration.uiMode = static_cast<uint8_t>(ui_mode);
439 configuration.colorMode = static_cast<uint8_t>(color_mode);
440 configuration.sdkVersion = static_cast<uint16_t>(major_version);
441
442 if (locale != nullptr) {
443 ScopedUtfChars locale_utf8(env, locale);
444 CHECK(locale_utf8.c_str() != nullptr);
445 configuration.setBcp47Locale(locale_utf8.c_str());
446 }
447
448 // Constants duplicated from Java class android.content.res.Configuration.
449 static const jint kScreenLayoutRoundMask = 0x300;
450 static const jint kScreenLayoutRoundShift = 8;
451
452 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
453 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
454 // into screenLayout2.
455 configuration.screenLayout2 =
456 static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
457
458 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
459 assetmanager->SetConfiguration(configuration);
460}
461
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800462static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
463 jboolean includeOverlays,
464 jboolean includeLoaders) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800465 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
466
467 jobject sparse_array =
468 env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
469
470 if (sparse_array == nullptr) {
471 // An exception is pending.
472 return nullptr;
473 }
474
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800475 // Optionally exclude overlays and loaders.
476 uint64_t exclusion_flags = ((includeOverlays) ? 0U : PROPERTY_OVERLAY)
477 | ((includeLoaders) ? 0U : PROPERTY_LOADER);
478
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800479 assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800480 jstring jpackage_name = env->NewStringUTF(package_name.c_str());
481 if (jpackage_name == nullptr) {
482 // An exception is pending.
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800483 return false;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800484 }
485
486 env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
487 jpackage_name);
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800488 return true;
Ryan Mitchell73bfe412019-11-12 16:22:04 -0800489 }, exclusion_flags);
490
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800491 return sparse_array;
492}
493
494static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
495 ScopedUtfChars path_utf8(env, path);
496 if (path_utf8.c_str() == nullptr) {
497 // This will throw NPE.
498 return nullptr;
499 }
500
501 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
502 std::unique_ptr<AssetDir> asset_dir =
503 assetmanager->OpenDir(path_utf8.c_str());
504 if (asset_dir == nullptr) {
505 jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
506 return nullptr;
507 }
508
509 const size_t file_count = asset_dir->getFileCount();
510
511 jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
512 if (array == nullptr) {
513 return nullptr;
514 }
515
516 for (size_t i = 0; i < file_count; i++) {
517 jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
518
519 // Check for errors creating the strings (if malformed or no memory).
520 if (env->ExceptionCheck()) {
521 return nullptr;
522 }
523
524 env->SetObjectArrayElement(array, i, java_string);
525
526 // If we have a large amount of string in our array, we might overflow the
527 // local reference table of the VM.
528 env->DeleteLocalRef(java_string);
529 }
530 return array;
531}
532
533static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
534 jint access_mode) {
535 ScopedUtfChars asset_path_utf8(env, asset_path);
536 if (asset_path_utf8.c_str() == nullptr) {
537 // This will throw NPE.
538 return 0;
539 }
540
541 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
542
543 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
544 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
545 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
546 return 0;
547 }
548
549 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
550 std::unique_ptr<Asset> asset =
551 assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
552 if (!asset) {
553 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
554 return 0;
555 }
556 return reinterpret_cast<jlong>(asset.release());
557}
558
559static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
560 jlongArray out_offsets) {
561 ScopedUtfChars asset_path_utf8(env, asset_path);
562 if (asset_path_utf8.c_str() == nullptr) {
563 // This will throw NPE.
564 return nullptr;
565 }
566
567 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
568
569 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
570 std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
571 if (!asset) {
572 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
573 return nullptr;
574 }
575 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
576}
577
578static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
579 jstring asset_path, jint access_mode) {
580 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
581 ScopedUtfChars asset_path_utf8(env, asset_path);
582 if (asset_path_utf8.c_str() == nullptr) {
583 // This will throw NPE.
584 return 0;
585 }
586
587 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
588
589 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
590 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
591 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
592 return 0;
593 }
594
595 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
596 std::unique_ptr<Asset> asset;
597 if (cookie != kInvalidCookie) {
598 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
599 static_cast<Asset::AccessMode>(access_mode));
600 } else {
601 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
602 static_cast<Asset::AccessMode>(access_mode));
603 }
604
605 if (!asset) {
606 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
607 return 0;
608 }
609 return reinterpret_cast<jlong>(asset.release());
610}
611
612static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
613 jstring asset_path, jlongArray out_offsets) {
614 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
615 ScopedUtfChars asset_path_utf8(env, asset_path);
616 if (asset_path_utf8.c_str() == nullptr) {
617 // This will throw NPE.
618 return nullptr;
619 }
620
621 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
622
623 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
624 std::unique_ptr<Asset> asset;
625 if (cookie != kInvalidCookie) {
626 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
627 } else {
628 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
629 }
630
631 if (!asset) {
632 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
633 return nullptr;
634 }
635 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
636}
637
638static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
639 jstring asset_path) {
640 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
641 ScopedUtfChars asset_path_utf8(env, asset_path);
642 if (asset_path_utf8.c_str() == nullptr) {
643 // This will throw NPE.
644 return 0;
645 }
646
647 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
648
649 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
650 std::unique_ptr<Asset> asset;
651 if (cookie != kInvalidCookie) {
652 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
653 } else {
654 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
655 }
656
657 if (!asset) {
658 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
659 return 0;
660 }
661
662 // May be nullptr.
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700663 std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
664 assetmanager->GetDynamicRefTableForCookie(cookie);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800665
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700666 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
667 std::move(dynamic_ref_table));
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800668 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
669 asset.reset();
670
671 if (err != NO_ERROR) {
672 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
673 return 0;
674 }
675 return reinterpret_cast<jlong>(xml_tree.release());
676}
677
Winson9947f1e2019-08-16 10:20:39 -0700678static jlong NativeOpenXmlAssetFd(JNIEnv* env, jobject /*clazz*/, jlong ptr, int jcookie,
679 jobject file_descriptor) {
680 int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
681 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAssetFd(%d)", fd).c_str());
682 if (fd < 0) {
683 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
684 return 0;
685 }
686
687 base::unique_fd dup_fd(::fcntl(fd, F_DUPFD_CLOEXEC, 0));
688 if (dup_fd < 0) {
689 jniThrowIOException(env, errno);
690 return 0;
691 }
692
693 std::unique_ptr<Asset>
694 asset(Asset::createFromFd(dup_fd.release(), nullptr, Asset::AccessMode::ACCESS_BUFFER));
695
696 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
697 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
698
699 // May be nullptr.
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700700 std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
701 assetmanager->GetDynamicRefTableForCookie(cookie);
Winson9947f1e2019-08-16 10:20:39 -0700702
Ryan Mitchell8a891d82019-07-01 09:48:23 -0700703 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
704 std::move(dynamic_ref_table));
Winson9947f1e2019-08-16 10:20:39 -0700705 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
706 asset.reset();
707
708 if (err != NO_ERROR) {
709 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
710 return 0;
711 }
712 return reinterpret_cast<jlong>(xml_tree.release());
713}
714
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800715static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
716 jshort density, jobject typed_value,
717 jboolean resolve_references) {
718 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
719 Res_value value;
720 ResTable_config selected_config;
721 uint32_t flags;
722 ApkAssetsCookie cookie =
723 assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
724 static_cast<uint16_t>(density), &value, &selected_config, &flags);
725 if (cookie == kInvalidCookie) {
726 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
727 }
728
729 uint32_t ref = static_cast<uint32_t>(resid);
730 if (resolve_references) {
731 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
732 if (cookie == kInvalidCookie) {
733 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
734 }
735 }
736 return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
737}
738
739static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
740 jint bag_entry_id, jobject typed_value) {
741 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
742 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
743 if (bag == nullptr) {
744 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
745 }
746
747 uint32_t type_spec_flags = bag->type_spec_flags;
748 ApkAssetsCookie cookie = kInvalidCookie;
749 const Res_value* bag_value = nullptr;
750 for (const ResolvedBag::Entry& entry : bag) {
751 if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
752 cookie = entry.cookie;
753 bag_value = &entry.value;
754
755 // Keep searching (the old implementation did that).
756 }
757 }
758
759 if (cookie == kInvalidCookie) {
760 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
761 }
762
763 Res_value value = *bag_value;
764 uint32_t ref = static_cast<uint32_t>(resid);
765 ResTable_config selected_config;
766 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
767 if (cookie == kInvalidCookie) {
768 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
769 }
770 return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
771}
772
773static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
774 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
775 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
776 if (bag == nullptr) {
777 return nullptr;
778 }
779
780 jintArray array = env->NewIntArray(bag->entry_count);
781 if (env->ExceptionCheck()) {
782 return nullptr;
783 }
784
785 for (uint32_t i = 0; i < bag->entry_count; i++) {
786 jint attr_resid = bag->entries[i].key;
787 env->SetIntArrayRegion(array, i, 1, &attr_resid);
788 }
789 return array;
790}
791
792static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
793 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 jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
801 if (array == nullptr) {
802 return nullptr;
803 }
804
805 for (uint32_t i = 0; i < bag->entry_count; i++) {
806 const ResolvedBag::Entry& entry = bag->entries[i];
807
808 // Resolve any references to their final value.
809 Res_value value = entry.value;
810 ResTable_config selected_config;
811 uint32_t flags;
812 uint32_t ref;
813 ApkAssetsCookie cookie =
814 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
815 if (cookie == kInvalidCookie) {
816 return nullptr;
817 }
818
819 if (value.dataType == Res_value::TYPE_STRING) {
820 const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
821 const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
822
823 jstring java_string = nullptr;
824 size_t str_len;
825 const char* str_utf8 = pool->string8At(value.data, &str_len);
826 if (str_utf8 != nullptr) {
827 java_string = env->NewStringUTF(str_utf8);
828 } else {
829 const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
830 java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
831 }
832
833 // Check for errors creating the strings (if malformed or no memory).
834 if (env->ExceptionCheck()) {
835 return nullptr;
836 }
837
838 env->SetObjectArrayElement(array, i, java_string);
839
840 // If we have a large amount of string in our array, we might overflow the
841 // local reference table of the VM.
842 env->DeleteLocalRef(java_string);
843 }
844 }
845 return array;
846}
847
848static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
849 jint resid) {
850 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
851 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
852 if (bag == nullptr) {
853 return nullptr;
854 }
855
856 jintArray array = env->NewIntArray(bag->entry_count * 2);
857 if (array == nullptr) {
858 return nullptr;
859 }
860
861 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
862 if (buffer == nullptr) {
863 return nullptr;
864 }
865
866 for (size_t i = 0; i < bag->entry_count; i++) {
867 const ResolvedBag::Entry& entry = bag->entries[i];
868 Res_value value = entry.value;
869 ResTable_config selected_config;
870 uint32_t flags;
871 uint32_t ref;
872 ApkAssetsCookie cookie =
873 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
874 if (cookie == kInvalidCookie) {
875 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
876 return nullptr;
877 }
878
879 jint string_index = -1;
880 if (value.dataType == Res_value::TYPE_STRING) {
881 string_index = static_cast<jint>(value.data);
882 }
883
884 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
885 buffer[(i * 2) + 1] = string_index;
886 }
887 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
888 return array;
889}
890
891static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
892 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
893 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
894 if (bag == nullptr) {
895 return nullptr;
896 }
897
898 jintArray array = env->NewIntArray(bag->entry_count);
899 if (array == nullptr) {
900 return nullptr;
901 }
902
903 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
904 if (buffer == nullptr) {
905 return nullptr;
906 }
907
908 for (size_t i = 0; i < bag->entry_count; i++) {
909 const ResolvedBag::Entry& entry = bag->entries[i];
910 Res_value value = entry.value;
911 ResTable_config selected_config;
912 uint32_t flags;
913 uint32_t ref;
914 ApkAssetsCookie cookie =
915 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
916 if (cookie == kInvalidCookie) {
917 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
918 return nullptr;
919 }
920
921 if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
922 buffer[i] = static_cast<jint>(value.data);
923 }
924 }
925 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
926 return array;
927}
928
929static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
930 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
931 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
932 if (bag == nullptr) {
933 return -1;
934 }
935 return static_cast<jint>(bag->entry_count);
936}
937
938static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
939 jintArray out_data) {
940 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
941 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
942 if (bag == nullptr) {
943 return -1;
944 }
945
946 const jsize out_data_length = env->GetArrayLength(out_data);
947 if (env->ExceptionCheck()) {
948 return -1;
949 }
950
951 if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
952 jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
953 return -1;
954 }
955
956 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
957 if (buffer == nullptr) {
958 return -1;
959 }
960
961 jint* cursor = buffer;
962 for (size_t i = 0; i < bag->entry_count; i++) {
963 const ResolvedBag::Entry& entry = bag->entries[i];
964 Res_value value = entry.value;
965 ResTable_config selected_config;
966 selected_config.density = 0;
967 uint32_t flags = bag->type_spec_flags;
Todd Kennedy1d63cc32018-04-18 10:25:45 -0700968 uint32_t ref = 0;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800969 ApkAssetsCookie cookie =
970 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
971 if (cookie == kInvalidCookie) {
972 env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
973 return -1;
974 }
975
976 // Deal with the special @null value -- it turns back to TYPE_NULL.
977 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
978 value.dataType = Res_value::TYPE_NULL;
979 value.data = Res_value::DATA_NULL_UNDEFINED;
980 }
981
982 cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
983 cursor[STYLE_DATA] = static_cast<jint>(value.data);
984 cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
985 cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
986 cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
987 cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
988 cursor += STYLE_NUM_ENTRIES;
989 }
990 env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
991 return static_cast<jint>(bag->entry_count);
992}
993
994static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
995 jstring def_type, jstring def_package) {
996 ScopedUtfChars name_utf8(env, name);
997 if (name_utf8.c_str() == nullptr) {
998 // This will throw NPE.
999 return 0;
1000 }
1001
1002 std::string type;
1003 if (def_type != nullptr) {
1004 ScopedUtfChars type_utf8(env, def_type);
1005 CHECK(type_utf8.c_str() != nullptr);
1006 type = type_utf8.c_str();
1007 }
1008
1009 std::string package;
1010 if (def_package != nullptr) {
1011 ScopedUtfChars package_utf8(env, def_package);
1012 CHECK(package_utf8.c_str() != nullptr);
1013 package = package_utf8.c_str();
1014 }
1015 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1016 return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
1017}
1018
1019static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1020 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1021 AssetManager2::ResourceName name;
1022 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1023 return nullptr;
1024 }
1025
Winson2f3669b2019-01-11 11:28:34 -08001026 std::string result = ToFormattedResourceString(&name);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001027 return env->NewStringUTF(result.c_str());
1028}
1029
1030static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1031 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1032 AssetManager2::ResourceName name;
1033 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1034 return nullptr;
1035 }
1036
1037 if (name.package != nullptr) {
1038 return env->NewStringUTF(name.package);
1039 }
1040 return nullptr;
1041}
1042
1043static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
1044 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1045 AssetManager2::ResourceName name;
1046 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
1047 return nullptr;
1048 }
1049
1050 if (name.type != nullptr) {
1051 return env->NewStringUTF(name.type);
1052 } else if (name.type16 != nullptr) {
1053 return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
1054 }
1055 return nullptr;
1056}
1057
1058static jstring NativeGetResourceEntryName(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.entry != nullptr) {
1066 return env->NewStringUTF(name.entry);
1067 } else if (name.entry16 != nullptr) {
1068 return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
1069 }
1070 return nullptr;
1071}
1072
Winson2f3669b2019-01-11 11:28:34 -08001073static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/,
1074 jclass /*clazz*/,
1075 jlong ptr,
1076 jboolean enabled) {
1077 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1078 assetmanager->SetResourceResolutionLoggingEnabled(enabled);
1079}
1080
1081static jstring NativeGetLastResourceResolution(JNIEnv* env,
1082 jclass /*clazz*/,
1083 jlong ptr) {
1084 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1085 std::string resolution = assetmanager->GetLastResourceResolution();
1086 if (resolution.empty()) {
1087 return nullptr;
1088 } else {
1089 return env->NewStringUTF(resolution.c_str());
1090 }
1091}
1092
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001093static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
1094 jboolean exclude_system) {
1095 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1096 std::set<std::string> locales =
1097 assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
1098
1099 jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
1100 if (array == nullptr) {
1101 return nullptr;
1102 }
1103
1104 size_t idx = 0;
1105 for (const std::string& locale : locales) {
1106 jstring java_string = env->NewStringUTF(locale.c_str());
1107 if (java_string == nullptr) {
1108 return nullptr;
1109 }
1110 env->SetObjectArrayElement(array, idx++, java_string);
1111 env->DeleteLocalRef(java_string);
1112 }
1113 return array;
1114}
1115
1116static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
1117 jobject result =
1118 env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1119 if (result == nullptr) {
1120 return nullptr;
1121 }
1122
1123 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1124 config.smallestScreenWidthDp);
1125 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1126 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1127 return result;
1128}
1129
1130static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1131 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1132 std::set<ResTable_config> configurations =
1133 assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1134
1135 jobjectArray array =
1136 env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1137 if (array == nullptr) {
1138 return nullptr;
1139 }
1140
1141 size_t idx = 0;
1142 for (const ResTable_config& configuration : configurations) {
1143 jobject java_configuration = ConstructConfigurationObject(env, configuration);
1144 if (java_configuration == nullptr) {
1145 return nullptr;
1146 }
1147
1148 env->SetObjectArrayElement(array, idx++, java_configuration);
1149 env->DeleteLocalRef(java_configuration);
1150 }
1151 return array;
1152}
1153
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001154static jintArray NativeAttributeResolutionStack(
1155 JNIEnv* env, jclass /*clazz*/, jlong ptr,
1156 jlong theme_ptr, jint xml_style_res,
1157 jint def_style_attr, jint def_style_resid) {
1158
1159 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1160 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1161 CHECK(theme->GetAssetManager() == &(*assetmanager));
1162 (void) assetmanager;
1163
1164 // Load default style from attribute, if specified...
1165 uint32_t def_style_flags = 0u;
1166 if (def_style_attr != 0) {
1167 Res_value value;
1168 if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
1169 if (value.dataType == Res_value::TYPE_REFERENCE) {
1170 def_style_resid = value.data;
1171 }
1172 }
1173 }
1174
1175 auto style_stack = assetmanager->GetBagResIdStack(xml_style_res);
1176 auto def_style_stack = assetmanager->GetBagResIdStack(def_style_resid);
1177
1178 jintArray array = env->NewIntArray(style_stack.size() + def_style_stack.size());
1179 if (env->ExceptionCheck()) {
1180 return nullptr;
1181 }
1182
1183 for (uint32_t i = 0; i < style_stack.size(); i++) {
1184 jint attr_resid = style_stack[i];
1185 env->SetIntArrayRegion(array, i, 1, &attr_resid);
1186 }
1187 for (uint32_t i = 0; i < def_style_stack.size(); i++) {
1188 jint attr_resid = def_style_stack[i];
1189 env->SetIntArrayRegion(array, style_stack.size() + i, 1, &attr_resid);
1190 }
1191 return array;
1192}
1193
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001194static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1195 jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1196 jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
1197 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1198 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1199 CHECK(theme->GetAssetManager() == &(*assetmanager));
1200 (void) assetmanager;
1201
1202 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1203 uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
1204 uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
1205
1206 jsize attrs_len = env->GetArrayLength(java_attrs);
1207 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1208 if (attrs == nullptr) {
1209 return;
1210 }
1211
1212 ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
1213 static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
1214 out_values, out_indices);
1215 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1216}
1217
1218static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1219 jint def_style_attr, jint def_style_resid, jintArray java_values,
1220 jintArray java_attrs, jintArray out_java_values,
1221 jintArray out_java_indices) {
1222 const jsize attrs_len = env->GetArrayLength(java_attrs);
1223 const jsize out_values_len = env->GetArrayLength(out_java_values);
1224 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1225 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1226 return JNI_FALSE;
1227 }
1228
1229 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1230 if (attrs == nullptr) {
1231 return JNI_FALSE;
1232 }
1233
1234 jint* values = nullptr;
1235 jsize values_len = 0;
1236 if (java_values != nullptr) {
1237 values_len = env->GetArrayLength(java_values);
1238 values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
1239 if (values == nullptr) {
1240 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1241 return JNI_FALSE;
1242 }
1243 }
1244
1245 jint* out_values =
1246 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1247 if (out_values == nullptr) {
1248 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1249 if (values != nullptr) {
1250 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1251 }
1252 return JNI_FALSE;
1253 }
1254
1255 jint* out_indices = nullptr;
1256 if (out_java_indices != nullptr) {
1257 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1258 if (out_indices_len > attrs_len) {
1259 out_indices =
1260 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1261 if (out_indices == nullptr) {
1262 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1263 if (values != nullptr) {
1264 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1265 }
1266 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1267 return JNI_FALSE;
1268 }
1269 }
1270 }
1271
1272 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1273 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1274 CHECK(theme->GetAssetManager() == &(*assetmanager));
1275 (void) assetmanager;
1276
1277 bool result = ResolveAttrs(
1278 theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1279 reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1280 attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1281 if (out_indices != nullptr) {
1282 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1283 }
1284
1285 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1286 if (values != nullptr) {
1287 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1288 }
1289 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1290 return result ? JNI_TRUE : JNI_FALSE;
1291}
1292
1293static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1294 jlong xml_parser_ptr, jintArray java_attrs,
1295 jintArray out_java_values, jintArray out_java_indices) {
1296 const jsize attrs_len = env->GetArrayLength(java_attrs);
1297 const jsize out_values_len = env->GetArrayLength(out_java_values);
1298 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1299 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1300 return JNI_FALSE;
1301 }
1302
1303 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1304 if (attrs == nullptr) {
1305 return JNI_FALSE;
1306 }
1307
1308 jint* out_values =
1309 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1310 if (out_values == nullptr) {
1311 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1312 return JNI_FALSE;
1313 }
1314
1315 jint* out_indices = nullptr;
1316 if (out_java_indices != nullptr) {
1317 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1318 if (out_indices_len > attrs_len) {
1319 out_indices =
1320 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1321 if (out_indices == nullptr) {
1322 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1323 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1324 return JNI_FALSE;
1325 }
1326 }
1327 }
1328
1329 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1330 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1331
1332 bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1333 reinterpret_cast<uint32_t*>(attrs), attrs_len,
1334 reinterpret_cast<uint32_t*>(out_values),
1335 reinterpret_cast<uint32_t*>(out_indices));
1336
1337 if (out_indices != nullptr) {
1338 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1339 }
1340 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1341 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1342 return result ? JNI_TRUE : JNI_FALSE;
1343}
1344
1345static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1346 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1347 return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1348}
1349
1350static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1351 delete reinterpret_cast<Theme*>(theme_ptr);
1352}
1353
1354static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1355 jint resid, jboolean force) {
1356 // AssetManager is accessed via the theme, so grab an explicit lock here.
1357 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1358 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1359 CHECK(theme->GetAssetManager() == &(*assetmanager));
1360 (void) assetmanager;
1361 theme->ApplyStyle(static_cast<uint32_t>(resid), force);
1362
1363 // TODO(adamlesinski): Consider surfacing exception when result is failure.
1364 // CTS currently expects no exceptions from this method.
1365 // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1366 // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
1367}
1368
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001369static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1370 jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001371 Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1372 Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001373
1374 if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1375 ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
1376 CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
1377 (void) dst_assetmanager;
1378
1379 ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
1380 CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
1381 (void) src_assetmanager;
1382
1383 dst_theme->SetTo(*src_theme);
1384 } else {
1385 dst_theme->SetTo(*src_theme);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001386 }
1387}
1388
1389static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1390 reinterpret_cast<Theme*>(theme_ptr)->Clear();
1391}
1392
1393static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1394 jint resid, jobject typed_value,
1395 jboolean resolve_references) {
1396 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1397 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1398 CHECK(theme->GetAssetManager() == &(*assetmanager));
1399 (void) assetmanager;
1400
1401 Res_value value;
1402 uint32_t flags;
1403 ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1404 if (cookie == kInvalidCookie) {
1405 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1406 }
1407
1408 uint32_t ref = 0u;
1409 if (resolve_references) {
1410 ResTable_config selected_config;
1411 cookie =
1412 theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1413 if (cookie == kInvalidCookie) {
1414 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1415 }
1416 }
1417 return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1418}
1419
1420static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1421 jint priority, jstring tag, jstring prefix) {
1422 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1423 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1424 CHECK(theme->GetAssetManager() == &(*assetmanager));
1425 (void) assetmanager;
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001426 (void) priority;
1427 (void) tag;
1428 (void) prefix;
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001429
1430 theme->Dump();
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001431}
1432
1433static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1434 jlong theme_ptr) {
1435 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1436 return static_cast<jint>(theme->GetChangingConfigurations());
1437}
1438
1439static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1440 delete reinterpret_cast<Asset*>(asset_ptr);
1441}
1442
1443static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1444 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1445 uint8_t b;
1446 ssize_t res = asset->read(&b, sizeof(b));
1447 return res == sizeof(b) ? static_cast<jint>(b) : -1;
1448}
1449
1450static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1451 jint offset, jint len) {
1452 if (len == 0) {
1453 return 0;
1454 }
1455
1456 jsize buffer_len = env->GetArrayLength(java_buffer);
1457 if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1458 offset > buffer_len - len) {
1459 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1460 return -1;
1461 }
1462
1463 ScopedByteArrayRW byte_array(env, java_buffer);
1464 if (byte_array.get() == nullptr) {
1465 return -1;
1466 }
1467
1468 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1469 ssize_t res = asset->read(byte_array.get() + offset, len);
1470 if (res < 0) {
1471 jniThrowException(env, "java/io/IOException", "");
1472 return -1;
1473 }
1474 return res > 0 ? static_cast<jint>(res) : -1;
1475}
1476
1477static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1478 jint whence) {
1479 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1480 return static_cast<jlong>(asset->seek(
1481 static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1482}
1483
1484static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1485 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1486 return static_cast<jlong>(asset->getLength());
1487}
1488
1489static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1490 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1491 return static_cast<jlong>(asset->getRemainingLength());
1492}
1493
1494// ----------------------------------------------------------------------------
1495
1496// JNI registration.
1497static const JNINativeMethod gAssetManagerMethods[] = {
1498 // AssetManager setup methods.
1499 {"nativeCreate", "()J", (void*)NativeCreate},
1500 {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1501 {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1502 {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1503 (void*)NativeSetConfiguration},
Ryan Mitchell73bfe412019-11-12 16:22:04 -08001504 {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001505 (void*)NativeGetAssignedPackageIdentifiers},
1506
1507 // AssetManager file methods.
1508 {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1509 {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1510 {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1511 (void*)NativeOpenAssetFd},
1512 {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1513 {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1514 (void*)NativeOpenNonAssetFd},
1515 {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
Winson9947f1e2019-08-16 10:20:39 -07001516 {"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001517
1518 // AssetManager resource methods.
1519 {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1520 {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1521 (void*)NativeGetResourceBagValue},
1522 {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1523 {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1524 (void*)NativeGetResourceStringArray},
1525 {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1526 {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1527 {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1528 {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1529
1530 // AssetManager resource name/ID methods.
1531 {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1532 (void*)NativeGetResourceIdentifier},
1533 {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1534 {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1535 {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1536 {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
Winson2f3669b2019-01-11 11:28:34 -08001537 {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
1538 (void*) NativeSetResourceResolutionLoggingEnabled},
1539 {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
1540 (void*) NativeGetLastResourceResolution},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001541 {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1542 {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1543 (void*)NativeGetSizeConfigurations},
1544
1545 // Style attribute related methods.
Aurimas Liutikas8f004c82019-01-17 17:20:10 -08001546 {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001547 {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1548 {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1549 {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1550
1551 // Theme related methods.
1552 {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1553 {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1554 {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001555 {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001556 {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1557 {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1558 (void*)NativeThemeGetAttributeValue},
1559 {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1560 {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1561
1562 // AssetInputStream methods.
1563 {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1564 {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1565 {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1566 {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1567 {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1568 {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1569
1570 // System/idmap related methods.
Mårten Kongstad06a1ac82018-09-20 13:09:47 +02001571 {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
1572 (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +01001573 {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
1574 (void*)NativeGetOverlayableMap},
Ryan Mitchell2e394222019-08-28 12:10:51 -07001575 {"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
1576 (void*)NativeGetOverlayablesToString},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001577
1578 // Global management/debug methods.
1579 {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1580 {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1581 {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1582};
1583
1584int register_android_content_AssetManager(JNIEnv* env) {
1585 jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1586 gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1587
1588 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1589 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1590 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1591 gTypedValueOffsets.mString =
1592 GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1593 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1594 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1595 gTypedValueOffsets.mChangingConfigurations =
1596 GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1597 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1598
1599 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1600 gAssetFileDescriptorOffsets.mFd =
1601 GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1602 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1603 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1604
1605 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1606 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1607
1608 jclass stringClass = FindClassOrDie(env, "java/lang/String");
1609 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1610
1611 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1612 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1613 gSparseArrayOffsets.constructor =
1614 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1615 gSparseArrayOffsets.put =
1616 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1617
1618 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1619 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1620 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1621 gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1622 GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1623 gConfigurationOffsets.mScreenWidthDpOffset =
1624 GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1625 gConfigurationOffsets.mScreenHeightDpOffset =
1626 GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1627
Mårten Kongstadc92c4dd2019-02-05 01:29:59 +01001628 jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
1629 gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
1630 gArrayMapOffsets.constructor =
1631 GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V");
1632 gArrayMapOffsets.put =
1633 GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put",
1634 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
1635
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001636 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1637 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638}
1639
1640}; // namespace android