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