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