blob: b2d44e73d8619baa3fb29a41afe118371a48acce [file] [log] [blame]
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001/*
2 * Copyright 2006, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080016
Adam Lesinskibebfcc42018-02-12 14:27:46 -080017#define ATRACE_TAG ATRACE_TAG_RESOURCES
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#define LOG_TAG "asset"
19
Dan Albert46d84442014-11-18 16:07:51 -080020#include <inttypes.h>
21#include <linux/capability.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022#include <stdio.h>
Adam Lesinskibde1df22018-02-09 11:12:22 -080023#include <sys/stat.h>
24#include <sys/system_properties.h>
Adam Lesinskibebfcc42018-02-12 14:27:46 -080025#include <sys/types.h>
26#include <sys/wait.h>
Mårten Kongstad48d22322014-01-31 14:43:27 +010027
Dan Albert46d84442014-11-18 16:07:51 -080028#include <private/android_filesystem_config.h> // for AID_SYSTEM
29
Adam Lesinskibebfcc42018-02-12 14:27:46 -080030#include "android-base/logging.h"
31#include "android-base/properties.h"
32#include "android-base/stringprintf.h"
33#include "android_runtime/android_util_AssetManager.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080034#include "android_runtime/AndroidRuntime.h"
35#include "android_util_Binder.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080036#include "androidfw/Asset.h"
37#include "androidfw/AssetManager.h"
38#include "androidfw/AssetManager2.h"
39#include "androidfw/AttributeResolution.h"
40#include "androidfw/MutexGuard.h"
41#include "androidfw/ResourceTypes.h"
Dan Albert3a091b72014-11-20 15:41:25 -080042#include "core_jni_helpers.h"
43#include "jni.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080044#include "nativehelper/JNIHelp.h"
45#include "nativehelper/ScopedPrimitiveArray.h"
46#include "nativehelper/ScopedStringChars.h"
47#include "nativehelper/ScopedUtfChars.h"
Dan Albert46d84442014-11-18 16:07:51 -080048#include "utils/Log.h"
Adam Lesinski11875902017-01-23 12:58:11 -080049#include "utils/misc.h"
Adam Lesinskibde1df22018-02-09 11:12:22 -080050#include "utils/String8.h"
Adam Lesinskibebfcc42018-02-12 14:27:46 -080051#include "utils/Trace.h"
Dan Albert46d84442014-11-18 16:07:51 -080052
Mårten Kongstad48d22322014-01-31 14:43:27 +010053extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
54extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
55
Adam Lesinskibebfcc42018-02-12 14:27:46 -080056using ::android::base::StringPrintf;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
58namespace android {
59
60// ----------------------------------------------------------------------------
61
Adam Lesinskibebfcc42018-02-12 14:27:46 -080062static struct typedvalue_offsets_t {
63 jfieldID mType;
64 jfieldID mData;
65 jfieldID mString;
66 jfieldID mAssetCookie;
67 jfieldID mResourceId;
68 jfieldID mChangingConfigurations;
69 jfieldID mDensity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070} gTypedValueOffsets;
71
Adam Lesinskibebfcc42018-02-12 14:27:46 -080072static struct assetfiledescriptor_offsets_t {
73 jfieldID mFd;
74 jfieldID mStartOffset;
75 jfieldID mLength;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076} gAssetFileDescriptorOffsets;
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
Adam Lesinskibebfcc42018-02-12 14:27:46 -080099jclass g_stringClass = nullptr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101// ----------------------------------------------------------------------------
102
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800103// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
104constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
105 return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
106}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800108constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
109 return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110}
111
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900112// This is called by zygote (running as user root) as part of preloadResources.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800113static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
114 switch (pid_t pid = fork()) {
115 case -1:
116 PLOG(ERROR) << "failed to fork for idmap";
117 break;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900118
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800119 // child
120 case 0: {
121 struct __user_cap_header_struct capheader;
122 struct __user_cap_data_struct capdata;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900123
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800124 memset(&capheader, 0, sizeof(capheader));
125 memset(&capdata, 0, sizeof(capdata));
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900126
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800127 capheader.version = _LINUX_CAPABILITY_VERSION;
128 capheader.pid = 0;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900129
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800130 if (capget(&capheader, &capdata) != 0) {
131 PLOG(ERROR) << "capget";
132 exit(1);
133 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900134
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800135 capdata.effective = capdata.permitted;
136 if (capset(&capheader, &capdata) != 0) {
137 PLOG(ERROR) << "capset";
138 exit(1);
139 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900140
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800141 if (setgid(AID_SYSTEM) != 0) {
142 PLOG(ERROR) << "setgid";
143 exit(1);
144 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900145
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800146 if (setuid(AID_SYSTEM) != 0) {
147 PLOG(ERROR) << "setuid";
148 exit(1);
149 }
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900150
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800151 // Generic idmap parameters
152 const char* argv[8];
153 int argc = 0;
154 struct stat st;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900155
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800156 memset(argv, 0, sizeof(argv));
157 argv[argc++] = AssetManager::IDMAP_BIN;
158 argv[argc++] = "--scan";
159 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
160 argv[argc++] = AssetManager::TARGET_APK_PATH;
161 argv[argc++] = AssetManager::IDMAP_DIR;
Jaekyun Seok7de2f9c2017-03-02 12:45:10 +0900162
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800163 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
164 // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
165 std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
166 "");
167 if (!overlay_theme_path.empty()) {
168 overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
169 if (stat(overlay_theme_path.c_str(), &st) == 0) {
170 argv[argc++] = overlay_theme_path.c_str();
Adam Lesinskiec7f06c2018-02-09 11:01:26 -0800171 }
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800172 }
Adam Lesinski11875902017-01-23 12:58:11 -0800173
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800174 if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
175 argv[argc++] = AssetManager::OVERLAY_DIR;
176 }
Adam Lesinski11875902017-01-23 12:58:11 -0800177
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800178 if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
179 argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
180 }
181
Dario Freni4ce46792018-06-01 14:02:08 +0100182 if (stat(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR, &st) == 0) {
183 argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
184 }
185
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800186 // Finally, invoke idmap (if any overlay directory exists)
187 if (argc > 5) {
188 execv(AssetManager::IDMAP_BIN, (char* const*)argv);
189 PLOG(ERROR) << "failed to execv for idmap";
190 exit(1); // should never get here
191 } else {
192 exit(0);
193 }
194 } break;
195
196 // parent
197 default:
198 waitpid(pid, nullptr, 0);
199 break;
200 }
Adam Lesinski11875902017-01-23 12:58:11 -0800201}
202
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800203static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
204 uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
205 env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
206 env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
207 ApkAssetsCookieToJavaCookie(cookie));
208 env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
209 env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
210 env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
211 env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
212 if (config != nullptr) {
213 env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
214 }
215 return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
Adam Lesinski11875902017-01-23 12:58:11 -0800216}
217
218// ----------------------------------------------------------------------------
219
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800220// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
221struct GuardedAssetManager : public ::AAssetManager {
222 Guarded<AssetManager2> guarded_assetmanager;
Adam Lesinski11875902017-01-23 12:58:11 -0800223};
224
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800225::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
226 jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
227 ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
228 if (am == nullptr) {
229 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
230 return nullptr;
231 }
232 return am;
233}
Adam Lesinski11875902017-01-23 12:58:11 -0800234
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800235Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
236 if (assetmanager == nullptr) {
237 return nullptr;
238 }
239 return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
240}
Adam Lesinski11875902017-01-23 12:58:11 -0800241
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800242Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
243 return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
244}
Adam Lesinski11875902017-01-23 12:58:11 -0800245
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800246static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
247 return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
248}
Adam Lesinski11875902017-01-23 12:58:11 -0800249
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800250static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
251 jlongArray out_offsets) {
252 off64_t start_offset, length;
253 int fd = asset->openFileDescriptor(&start_offset, &length);
254 asset.reset();
Adam Lesinski11875902017-01-23 12:58:11 -0800255
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800256 if (fd < 0) {
257 jniThrowException(env, "java/io/FileNotFoundException",
258 "This file can not be opened as a file descriptor; it is probably "
259 "compressed");
260 return nullptr;
261 }
Adam Lesinski11875902017-01-23 12:58:11 -0800262
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800263 jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
264 if (offsets == nullptr) {
265 close(fd);
266 return nullptr;
267 }
268
269 offsets[0] = start_offset;
270 offsets[1] = length;
271
272 env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
273
274 jobject file_desc = jniCreateFileDescriptor(env, fd);
275 if (file_desc == nullptr) {
276 close(fd);
277 return nullptr;
278 }
279 return newParcelFileDescriptor(env, file_desc);
280}
281
282static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
283 return Asset::getGlobalCount();
284}
285
286static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
287 String8 alloc = Asset::getAssetAllocations();
288 if (alloc.length() <= 0) {
289 return nullptr;
290 }
291 return env->NewStringUTF(alloc.string());
292}
293
294static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
295 // TODO(adamlesinski): Switch to AssetManager2.
296 return AssetManager::getGlobalCount();
297}
298
299static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
300 // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
301 // AssetManager2 in a contiguous block (GuardedAssetManager).
302 return reinterpret_cast<jlong>(new GuardedAssetManager());
303}
304
305static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
306 delete reinterpret_cast<GuardedAssetManager*>(ptr);
307}
308
309static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
310 jobjectArray apk_assets_array, jboolean invalidate_caches) {
311 ATRACE_NAME("AssetManager::SetApkAssets");
312
313 const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
314 std::vector<const ApkAssets*> apk_assets;
315 apk_assets.reserve(apk_assets_len);
316 for (jsize i = 0; i < apk_assets_len; i++) {
317 jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
318 if (obj == nullptr) {
319 std::string msg = StringPrintf("ApkAssets at index %d is null", i);
320 jniThrowNullPointerException(env, msg.c_str());
321 return;
322 }
323
324 jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
325 if (env->ExceptionCheck()) {
326 return;
327 }
328 apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
329 }
330
331 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
332 assetmanager->SetApkAssets(apk_assets, invalidate_caches);
333}
334
335static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
336 jstring locale, jint orientation, jint touchscreen, jint density,
337 jint keyboard, jint keyboard_hidden, jint navigation,
338 jint screen_width, jint screen_height,
339 jint smallest_screen_width_dp, jint screen_width_dp,
340 jint screen_height_dp, jint screen_layout, jint ui_mode,
341 jint color_mode, jint major_version) {
342 ATRACE_NAME("AssetManager::SetConfiguration");
343
344 ResTable_config configuration;
345 memset(&configuration, 0, sizeof(configuration));
346 configuration.mcc = static_cast<uint16_t>(mcc);
347 configuration.mnc = static_cast<uint16_t>(mnc);
348 configuration.orientation = static_cast<uint8_t>(orientation);
349 configuration.touchscreen = static_cast<uint8_t>(touchscreen);
350 configuration.density = static_cast<uint16_t>(density);
351 configuration.keyboard = static_cast<uint8_t>(keyboard);
352 configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
353 configuration.navigation = static_cast<uint8_t>(navigation);
354 configuration.screenWidth = static_cast<uint16_t>(screen_width);
355 configuration.screenHeight = static_cast<uint16_t>(screen_height);
356 configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
357 configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
358 configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
359 configuration.screenLayout = static_cast<uint8_t>(screen_layout);
360 configuration.uiMode = static_cast<uint8_t>(ui_mode);
361 configuration.colorMode = static_cast<uint8_t>(color_mode);
362 configuration.sdkVersion = static_cast<uint16_t>(major_version);
363
364 if (locale != nullptr) {
365 ScopedUtfChars locale_utf8(env, locale);
366 CHECK(locale_utf8.c_str() != nullptr);
367 configuration.setBcp47Locale(locale_utf8.c_str());
368 }
369
370 // Constants duplicated from Java class android.content.res.Configuration.
371 static const jint kScreenLayoutRoundMask = 0x300;
372 static const jint kScreenLayoutRoundShift = 8;
373
374 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
375 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
376 // into screenLayout2.
377 configuration.screenLayout2 =
378 static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
379
380 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
381 assetmanager->SetConfiguration(configuration);
382}
383
384static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
385 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
386
387 jobject sparse_array =
388 env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
389
390 if (sparse_array == nullptr) {
391 // An exception is pending.
392 return nullptr;
393 }
394
395 assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
396 jstring jpackage_name = env->NewStringUTF(package_name.c_str());
397 if (jpackage_name == nullptr) {
398 // An exception is pending.
399 return;
400 }
401
402 env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
403 jpackage_name);
404 });
405 return sparse_array;
406}
407
408static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
409 ScopedUtfChars path_utf8(env, path);
410 if (path_utf8.c_str() == nullptr) {
411 // This will throw NPE.
412 return nullptr;
413 }
414
415 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
416 std::unique_ptr<AssetDir> asset_dir =
417 assetmanager->OpenDir(path_utf8.c_str());
418 if (asset_dir == nullptr) {
419 jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
420 return nullptr;
421 }
422
423 const size_t file_count = asset_dir->getFileCount();
424
425 jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
426 if (array == nullptr) {
427 return nullptr;
428 }
429
430 for (size_t i = 0; i < file_count; i++) {
431 jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
432
433 // Check for errors creating the strings (if malformed or no memory).
434 if (env->ExceptionCheck()) {
435 return nullptr;
436 }
437
438 env->SetObjectArrayElement(array, i, java_string);
439
440 // If we have a large amount of string in our array, we might overflow the
441 // local reference table of the VM.
442 env->DeleteLocalRef(java_string);
443 }
444 return array;
445}
446
447static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
448 jint access_mode) {
449 ScopedUtfChars asset_path_utf8(env, asset_path);
450 if (asset_path_utf8.c_str() == nullptr) {
451 // This will throw NPE.
452 return 0;
453 }
454
455 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAsset(%s)", asset_path_utf8.c_str()).c_str());
456
457 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
458 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
459 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
460 return 0;
461 }
462
463 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
464 std::unique_ptr<Asset> asset =
465 assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
466 if (!asset) {
467 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
468 return 0;
469 }
470 return reinterpret_cast<jlong>(asset.release());
471}
472
473static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
474 jlongArray out_offsets) {
475 ScopedUtfChars asset_path_utf8(env, asset_path);
476 if (asset_path_utf8.c_str() == nullptr) {
477 // This will throw NPE.
478 return nullptr;
479 }
480
481 ATRACE_NAME(base::StringPrintf("AssetManager::OpenAssetFd(%s)", asset_path_utf8.c_str()).c_str());
482
483 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
484 std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
485 if (!asset) {
486 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
487 return nullptr;
488 }
489 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
490}
491
492static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
493 jstring asset_path, jint access_mode) {
494 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
495 ScopedUtfChars asset_path_utf8(env, asset_path);
496 if (asset_path_utf8.c_str() == nullptr) {
497 // This will throw NPE.
498 return 0;
499 }
500
501 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAsset(%s)", asset_path_utf8.c_str()).c_str());
502
503 if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
504 access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
505 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
506 return 0;
507 }
508
509 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
510 std::unique_ptr<Asset> asset;
511 if (cookie != kInvalidCookie) {
512 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
513 static_cast<Asset::AccessMode>(access_mode));
514 } else {
515 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
516 static_cast<Asset::AccessMode>(access_mode));
517 }
518
519 if (!asset) {
520 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
521 return 0;
522 }
523 return reinterpret_cast<jlong>(asset.release());
524}
525
526static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
527 jstring asset_path, jlongArray out_offsets) {
528 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
529 ScopedUtfChars asset_path_utf8(env, asset_path);
530 if (asset_path_utf8.c_str() == nullptr) {
531 // This will throw NPE.
532 return nullptr;
533 }
534
535 ATRACE_NAME(base::StringPrintf("AssetManager::OpenNonAssetFd(%s)", asset_path_utf8.c_str()).c_str());
536
537 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
538 std::unique_ptr<Asset> asset;
539 if (cookie != kInvalidCookie) {
540 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
541 } else {
542 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
543 }
544
545 if (!asset) {
546 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
547 return nullptr;
548 }
549 return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
550}
551
552static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
553 jstring asset_path) {
554 ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
555 ScopedUtfChars asset_path_utf8(env, asset_path);
556 if (asset_path_utf8.c_str() == nullptr) {
557 // This will throw NPE.
558 return 0;
559 }
560
561 ATRACE_NAME(base::StringPrintf("AssetManager::OpenXmlAsset(%s)", asset_path_utf8.c_str()).c_str());
562
563 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
564 std::unique_ptr<Asset> asset;
565 if (cookie != kInvalidCookie) {
566 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
567 } else {
568 asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
569 }
570
571 if (!asset) {
572 jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
573 return 0;
574 }
575
576 // May be nullptr.
577 const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
578
579 std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
580 status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
581 asset.reset();
582
583 if (err != NO_ERROR) {
584 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
585 return 0;
586 }
587 return reinterpret_cast<jlong>(xml_tree.release());
588}
589
590static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
591 jshort density, jobject typed_value,
592 jboolean resolve_references) {
593 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
594 Res_value value;
595 ResTable_config selected_config;
596 uint32_t flags;
597 ApkAssetsCookie cookie =
598 assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
599 static_cast<uint16_t>(density), &value, &selected_config, &flags);
600 if (cookie == kInvalidCookie) {
601 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
602 }
603
604 uint32_t ref = static_cast<uint32_t>(resid);
605 if (resolve_references) {
606 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
607 if (cookie == kInvalidCookie) {
608 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
609 }
610 }
611 return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
612}
613
614static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
615 jint bag_entry_id, jobject typed_value) {
616 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
617 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
618 if (bag == nullptr) {
619 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
620 }
621
622 uint32_t type_spec_flags = bag->type_spec_flags;
623 ApkAssetsCookie cookie = kInvalidCookie;
624 const Res_value* bag_value = nullptr;
625 for (const ResolvedBag::Entry& entry : bag) {
626 if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
627 cookie = entry.cookie;
628 bag_value = &entry.value;
629
630 // Keep searching (the old implementation did that).
631 }
632 }
633
634 if (cookie == kInvalidCookie) {
635 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
636 }
637
638 Res_value value = *bag_value;
639 uint32_t ref = static_cast<uint32_t>(resid);
640 ResTable_config selected_config;
641 cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
642 if (cookie == kInvalidCookie) {
643 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
644 }
645 return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
646}
647
648static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
649 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
650 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
651 if (bag == nullptr) {
652 return nullptr;
653 }
654
655 jintArray array = env->NewIntArray(bag->entry_count);
656 if (env->ExceptionCheck()) {
657 return nullptr;
658 }
659
660 for (uint32_t i = 0; i < bag->entry_count; i++) {
661 jint attr_resid = bag->entries[i].key;
662 env->SetIntArrayRegion(array, i, 1, &attr_resid);
663 }
664 return array;
665}
666
667static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
668 jint resid) {
669 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
670 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
671 if (bag == nullptr) {
672 return nullptr;
673 }
674
675 jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
676 if (array == nullptr) {
677 return nullptr;
678 }
679
680 for (uint32_t i = 0; i < bag->entry_count; i++) {
681 const ResolvedBag::Entry& entry = bag->entries[i];
682
683 // Resolve any references to their final value.
684 Res_value value = entry.value;
685 ResTable_config selected_config;
686 uint32_t flags;
687 uint32_t ref;
688 ApkAssetsCookie cookie =
689 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
690 if (cookie == kInvalidCookie) {
691 return nullptr;
692 }
693
694 if (value.dataType == Res_value::TYPE_STRING) {
695 const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
696 const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
697
698 jstring java_string = nullptr;
699 size_t str_len;
700 const char* str_utf8 = pool->string8At(value.data, &str_len);
701 if (str_utf8 != nullptr) {
702 java_string = env->NewStringUTF(str_utf8);
703 } else {
704 const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
705 java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
706 }
707
708 // Check for errors creating the strings (if malformed or no memory).
709 if (env->ExceptionCheck()) {
710 return nullptr;
711 }
712
713 env->SetObjectArrayElement(array, i, java_string);
714
715 // If we have a large amount of string in our array, we might overflow the
716 // local reference table of the VM.
717 env->DeleteLocalRef(java_string);
718 }
719 }
720 return array;
721}
722
723static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
724 jint resid) {
725 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
726 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
727 if (bag == nullptr) {
728 return nullptr;
729 }
730
731 jintArray array = env->NewIntArray(bag->entry_count * 2);
732 if (array == nullptr) {
733 return nullptr;
734 }
735
736 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
737 if (buffer == nullptr) {
738 return nullptr;
739 }
740
741 for (size_t i = 0; i < bag->entry_count; i++) {
742 const ResolvedBag::Entry& entry = bag->entries[i];
743 Res_value value = entry.value;
744 ResTable_config selected_config;
745 uint32_t flags;
746 uint32_t ref;
747 ApkAssetsCookie cookie =
748 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
749 if (cookie == kInvalidCookie) {
750 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
751 return nullptr;
752 }
753
754 jint string_index = -1;
755 if (value.dataType == Res_value::TYPE_STRING) {
756 string_index = static_cast<jint>(value.data);
757 }
758
759 buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
760 buffer[(i * 2) + 1] = string_index;
761 }
762 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
763 return array;
764}
765
766static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
767 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
768 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
769 if (bag == nullptr) {
770 return nullptr;
771 }
772
773 jintArray array = env->NewIntArray(bag->entry_count);
774 if (array == nullptr) {
775 return nullptr;
776 }
777
778 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
779 if (buffer == nullptr) {
780 return nullptr;
781 }
782
783 for (size_t i = 0; i < bag->entry_count; i++) {
784 const ResolvedBag::Entry& entry = bag->entries[i];
785 Res_value value = entry.value;
786 ResTable_config selected_config;
787 uint32_t flags;
788 uint32_t ref;
789 ApkAssetsCookie cookie =
790 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
791 if (cookie == kInvalidCookie) {
792 env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
793 return nullptr;
794 }
795
796 if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
797 buffer[i] = static_cast<jint>(value.data);
798 }
799 }
800 env->ReleasePrimitiveArrayCritical(array, buffer, 0);
801 return array;
802}
803
804static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
805 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
806 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
807 if (bag == nullptr) {
808 return -1;
809 }
810 return static_cast<jint>(bag->entry_count);
811}
812
813static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
814 jintArray out_data) {
815 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
816 const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
817 if (bag == nullptr) {
818 return -1;
819 }
820
821 const jsize out_data_length = env->GetArrayLength(out_data);
822 if (env->ExceptionCheck()) {
823 return -1;
824 }
825
826 if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
827 jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
828 return -1;
829 }
830
831 jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
832 if (buffer == nullptr) {
833 return -1;
834 }
835
836 jint* cursor = buffer;
837 for (size_t i = 0; i < bag->entry_count; i++) {
838 const ResolvedBag::Entry& entry = bag->entries[i];
839 Res_value value = entry.value;
840 ResTable_config selected_config;
841 selected_config.density = 0;
842 uint32_t flags = bag->type_spec_flags;
Todd Kennedy1d63cc32018-04-18 10:25:45 -0700843 uint32_t ref = 0;
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800844 ApkAssetsCookie cookie =
845 assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
846 if (cookie == kInvalidCookie) {
847 env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
848 return -1;
849 }
850
851 // Deal with the special @null value -- it turns back to TYPE_NULL.
852 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
853 value.dataType = Res_value::TYPE_NULL;
854 value.data = Res_value::DATA_NULL_UNDEFINED;
855 }
856
857 cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
858 cursor[STYLE_DATA] = static_cast<jint>(value.data);
859 cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
860 cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
861 cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
862 cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
863 cursor += STYLE_NUM_ENTRIES;
864 }
865 env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
866 return static_cast<jint>(bag->entry_count);
867}
868
869static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
870 jstring def_type, jstring def_package) {
871 ScopedUtfChars name_utf8(env, name);
872 if (name_utf8.c_str() == nullptr) {
873 // This will throw NPE.
874 return 0;
875 }
876
877 std::string type;
878 if (def_type != nullptr) {
879 ScopedUtfChars type_utf8(env, def_type);
880 CHECK(type_utf8.c_str() != nullptr);
881 type = type_utf8.c_str();
882 }
883
884 std::string package;
885 if (def_package != nullptr) {
886 ScopedUtfChars package_utf8(env, def_package);
887 CHECK(package_utf8.c_str() != nullptr);
888 package = package_utf8.c_str();
889 }
890 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
891 return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
892}
893
894static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
895 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
896 AssetManager2::ResourceName name;
897 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
898 return nullptr;
899 }
900
901 std::string result;
902 if (name.package != nullptr) {
903 result.append(name.package, name.package_len);
904 }
905
906 if (name.type != nullptr || name.type16 != nullptr) {
907 if (!result.empty()) {
908 result += ":";
909 }
910
911 if (name.type != nullptr) {
912 result.append(name.type, name.type_len);
913 } else {
914 result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
915 }
916 }
917
918 if (name.entry != nullptr || name.entry16 != nullptr) {
919 if (!result.empty()) {
920 result += "/";
921 }
922
923 if (name.entry != nullptr) {
924 result.append(name.entry, name.entry_len);
925 } else {
926 result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
927 }
928 }
929 return env->NewStringUTF(result.c_str());
930}
931
932static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
933 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
934 AssetManager2::ResourceName name;
935 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
936 return nullptr;
937 }
938
939 if (name.package != nullptr) {
940 return env->NewStringUTF(name.package);
941 }
942 return nullptr;
943}
944
945static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
946 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
947 AssetManager2::ResourceName name;
948 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
949 return nullptr;
950 }
951
952 if (name.type != nullptr) {
953 return env->NewStringUTF(name.type);
954 } else if (name.type16 != nullptr) {
955 return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
956 }
957 return nullptr;
958}
959
960static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
961 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
962 AssetManager2::ResourceName name;
963 if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
964 return nullptr;
965 }
966
967 if (name.entry != nullptr) {
968 return env->NewStringUTF(name.entry);
969 } else if (name.entry16 != nullptr) {
970 return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
971 }
972 return nullptr;
973}
974
975static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
976 jboolean exclude_system) {
977 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
978 std::set<std::string> locales =
979 assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
980
981 jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
982 if (array == nullptr) {
983 return nullptr;
984 }
985
986 size_t idx = 0;
987 for (const std::string& locale : locales) {
988 jstring java_string = env->NewStringUTF(locale.c_str());
989 if (java_string == nullptr) {
990 return nullptr;
991 }
992 env->SetObjectArrayElement(array, idx++, java_string);
993 env->DeleteLocalRef(java_string);
994 }
995 return array;
996}
997
998static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
999 jobject result =
1000 env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
1001 if (result == nullptr) {
1002 return nullptr;
1003 }
1004
1005 env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
1006 config.smallestScreenWidthDp);
1007 env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
1008 env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
1009 return result;
1010}
1011
1012static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
1013 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1014 std::set<ResTable_config> configurations =
1015 assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
1016
1017 jobjectArray array =
1018 env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
1019 if (array == nullptr) {
1020 return nullptr;
1021 }
1022
1023 size_t idx = 0;
1024 for (const ResTable_config& configuration : configurations) {
1025 jobject java_configuration = ConstructConfigurationObject(env, configuration);
1026 if (java_configuration == nullptr) {
1027 return nullptr;
1028 }
1029
1030 env->SetObjectArrayElement(array, idx++, java_configuration);
1031 env->DeleteLocalRef(java_configuration);
1032 }
1033 return array;
1034}
1035
1036static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1037 jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
1038 jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
1039 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1040 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1041 CHECK(theme->GetAssetManager() == &(*assetmanager));
1042 (void) assetmanager;
1043
1044 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1045 uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
1046 uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
1047
1048 jsize attrs_len = env->GetArrayLength(java_attrs);
1049 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1050 if (attrs == nullptr) {
1051 return;
1052 }
1053
1054 ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
1055 static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
1056 out_values, out_indices);
1057 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1058}
1059
1060static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1061 jint def_style_attr, jint def_style_resid, jintArray java_values,
1062 jintArray java_attrs, jintArray out_java_values,
1063 jintArray out_java_indices) {
1064 const jsize attrs_len = env->GetArrayLength(java_attrs);
1065 const jsize out_values_len = env->GetArrayLength(out_java_values);
1066 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1067 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1068 return JNI_FALSE;
1069 }
1070
1071 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1072 if (attrs == nullptr) {
1073 return JNI_FALSE;
1074 }
1075
1076 jint* values = nullptr;
1077 jsize values_len = 0;
1078 if (java_values != nullptr) {
1079 values_len = env->GetArrayLength(java_values);
1080 values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
1081 if (values == nullptr) {
1082 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1083 return JNI_FALSE;
1084 }
1085 }
1086
1087 jint* out_values =
1088 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1089 if (out_values == nullptr) {
1090 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1091 if (values != nullptr) {
1092 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1093 }
1094 return JNI_FALSE;
1095 }
1096
1097 jint* out_indices = nullptr;
1098 if (out_java_indices != nullptr) {
1099 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1100 if (out_indices_len > attrs_len) {
1101 out_indices =
1102 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1103 if (out_indices == nullptr) {
1104 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1105 if (values != nullptr) {
1106 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1107 }
1108 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1109 return JNI_FALSE;
1110 }
1111 }
1112 }
1113
1114 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1115 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1116 CHECK(theme->GetAssetManager() == &(*assetmanager));
1117 (void) assetmanager;
1118
1119 bool result = ResolveAttrs(
1120 theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
1121 reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
1122 attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
1123 if (out_indices != nullptr) {
1124 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1125 }
1126
1127 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1128 if (values != nullptr) {
1129 env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
1130 }
1131 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1132 return result ? JNI_TRUE : JNI_FALSE;
1133}
1134
1135static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
1136 jlong xml_parser_ptr, jintArray java_attrs,
1137 jintArray out_java_values, jintArray out_java_indices) {
1138 const jsize attrs_len = env->GetArrayLength(java_attrs);
1139 const jsize out_values_len = env->GetArrayLength(out_java_values);
1140 if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
1141 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
1142 return JNI_FALSE;
1143 }
1144
1145 jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
1146 if (attrs == nullptr) {
1147 return JNI_FALSE;
1148 }
1149
1150 jint* out_values =
1151 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
1152 if (out_values == nullptr) {
1153 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1154 return JNI_FALSE;
1155 }
1156
1157 jint* out_indices = nullptr;
1158 if (out_java_indices != nullptr) {
1159 jsize out_indices_len = env->GetArrayLength(out_java_indices);
1160 if (out_indices_len > attrs_len) {
1161 out_indices =
1162 reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
1163 if (out_indices == nullptr) {
1164 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1165 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
1166 return JNI_FALSE;
1167 }
1168 }
1169 }
1170
1171 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1172 ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
1173
1174 bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
1175 reinterpret_cast<uint32_t*>(attrs), attrs_len,
1176 reinterpret_cast<uint32_t*>(out_values),
1177 reinterpret_cast<uint32_t*>(out_indices));
1178
1179 if (out_indices != nullptr) {
1180 env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
1181 }
1182 env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
1183 env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
1184 return result ? JNI_TRUE : JNI_FALSE;
1185}
1186
1187static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
1188 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1189 return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
1190}
1191
1192static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1193 delete reinterpret_cast<Theme*>(theme_ptr);
1194}
1195
1196static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1197 jint resid, jboolean force) {
1198 // AssetManager is accessed via the theme, so grab an explicit lock here.
1199 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1200 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1201 CHECK(theme->GetAssetManager() == &(*assetmanager));
1202 (void) assetmanager;
1203 theme->ApplyStyle(static_cast<uint32_t>(resid), force);
1204
1205 // TODO(adamlesinski): Consider surfacing exception when result is failure.
1206 // CTS currently expects no exceptions from this method.
1207 // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
1208 // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
1209}
1210
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001211static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_asset_manager_ptr,
1212 jlong dst_theme_ptr, jlong src_asset_manager_ptr, jlong src_theme_ptr) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001213 Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
1214 Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001215
1216 if (dst_asset_manager_ptr != src_asset_manager_ptr) {
1217 ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
1218 CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
1219 (void) dst_assetmanager;
1220
1221 ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
1222 CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
1223 (void) src_assetmanager;
1224
1225 dst_theme->SetTo(*src_theme);
1226 } else {
1227 dst_theme->SetTo(*src_theme);
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001228 }
1229}
1230
1231static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
1232 reinterpret_cast<Theme*>(theme_ptr)->Clear();
1233}
1234
1235static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1236 jint resid, jobject typed_value,
1237 jboolean resolve_references) {
1238 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1239 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1240 CHECK(theme->GetAssetManager() == &(*assetmanager));
1241 (void) assetmanager;
1242
1243 Res_value value;
1244 uint32_t flags;
1245 ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
1246 if (cookie == kInvalidCookie) {
1247 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1248 }
1249
1250 uint32_t ref = 0u;
1251 if (resolve_references) {
1252 ResTable_config selected_config;
1253 cookie =
1254 theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
1255 if (cookie == kInvalidCookie) {
1256 return ApkAssetsCookieToJavaCookie(kInvalidCookie);
1257 }
1258 }
1259 return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
1260}
1261
1262static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
1263 jint priority, jstring tag, jstring prefix) {
1264 ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
1265 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1266 CHECK(theme->GetAssetManager() == &(*assetmanager));
1267 (void) assetmanager;
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001268 (void) priority;
1269 (void) tag;
1270 (void) prefix;
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001271
1272 theme->Dump();
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001273}
1274
1275static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
1276 jlong theme_ptr) {
1277 Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
1278 return static_cast<jint>(theme->GetChangingConfigurations());
1279}
1280
1281static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1282 delete reinterpret_cast<Asset*>(asset_ptr);
1283}
1284
1285static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1286 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1287 uint8_t b;
1288 ssize_t res = asset->read(&b, sizeof(b));
1289 return res == sizeof(b) ? static_cast<jint>(b) : -1;
1290}
1291
1292static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
1293 jint offset, jint len) {
1294 if (len == 0) {
1295 return 0;
1296 }
1297
1298 jsize buffer_len = env->GetArrayLength(java_buffer);
1299 if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
1300 offset > buffer_len - len) {
1301 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
1302 return -1;
1303 }
1304
1305 ScopedByteArrayRW byte_array(env, java_buffer);
1306 if (byte_array.get() == nullptr) {
1307 return -1;
1308 }
1309
1310 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1311 ssize_t res = asset->read(byte_array.get() + offset, len);
1312 if (res < 0) {
1313 jniThrowException(env, "java/io/IOException", "");
1314 return -1;
1315 }
1316 return res > 0 ? static_cast<jint>(res) : -1;
1317}
1318
1319static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
1320 jint whence) {
1321 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1322 return static_cast<jlong>(asset->seek(
1323 static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
1324}
1325
1326static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1327 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1328 return static_cast<jlong>(asset->getLength());
1329}
1330
1331static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
1332 Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
1333 return static_cast<jlong>(asset->getRemainingLength());
1334}
1335
1336// ----------------------------------------------------------------------------
1337
1338// JNI registration.
1339static const JNINativeMethod gAssetManagerMethods[] = {
1340 // AssetManager setup methods.
1341 {"nativeCreate", "()J", (void*)NativeCreate},
1342 {"nativeDestroy", "(J)V", (void*)NativeDestroy},
1343 {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
1344 {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
1345 (void*)NativeSetConfiguration},
1346 {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
1347 (void*)NativeGetAssignedPackageIdentifiers},
1348
1349 // AssetManager file methods.
1350 {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
1351 {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
1352 {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1353 (void*)NativeOpenAssetFd},
1354 {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
1355 {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1356 (void*)NativeOpenNonAssetFd},
1357 {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
1358
1359 // AssetManager resource methods.
1360 {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
1361 {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
1362 (void*)NativeGetResourceBagValue},
1363 {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
1364 {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
1365 (void*)NativeGetResourceStringArray},
1366 {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
1367 {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
1368 {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
1369 {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
1370
1371 // AssetManager resource name/ID methods.
1372 {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1373 (void*)NativeGetResourceIdentifier},
1374 {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
1375 {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
1376 {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
1377 {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
1378 {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
1379 {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
1380 (void*)NativeGetSizeConfigurations},
1381
1382 // Style attribute related methods.
1383 {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
1384 {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
1385 {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
1386
1387 // Theme related methods.
1388 {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
1389 {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
1390 {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
Ryan Mitchellb3ae42e2018-10-16 12:48:38 -07001391 {"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
Adam Lesinskibebfcc42018-02-12 14:27:46 -08001392 {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
1393 {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
1394 (void*)NativeThemeGetAttributeValue},
1395 {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
1396 {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
1397
1398 // AssetInputStream methods.
1399 {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
1400 {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
1401 {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
1402 {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
1403 {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
1404 {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
1405
1406 // System/idmap related methods.
1407 {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
1408
1409 // Global management/debug methods.
1410 {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
1411 {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
1412 {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
1413};
1414
1415int register_android_content_AssetManager(JNIEnv* env) {
1416 jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
1417 gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
1418
1419 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
1420 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
1421 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
1422 gTypedValueOffsets.mString =
1423 GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
1424 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
1425 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
1426 gTypedValueOffsets.mChangingConfigurations =
1427 GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
1428 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
1429
1430 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
1431 gAssetFileDescriptorOffsets.mFd =
1432 GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1433 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
1434 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
1435
1436 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
1437 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
1438
1439 jclass stringClass = FindClassOrDie(env, "java/lang/String");
1440 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
1441
1442 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
1443 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
1444 gSparseArrayOffsets.constructor =
1445 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
1446 gSparseArrayOffsets.put =
1447 GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
1448
1449 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
1450 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
1451 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
1452 gConfigurationOffsets.mSmallestScreenWidthDpOffset =
1453 GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
1454 gConfigurationOffsets.mScreenWidthDpOffset =
1455 GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
1456 gConfigurationOffsets.mScreenHeightDpOffset =
1457 GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
1458
1459 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
1460 NELEM(gAssetManagerMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461}
1462
1463}; // namespace android