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