1 /* //device/libs/android_runtime/android_util_AssetManager.cpp
3 ** Copyright 2006, The Android Open Source Project
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
9 ** http://www.apache.org/licenses/LICENSE-2.0
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
18 #define LOG_TAG "asset"
20 #include <android_runtime/android_util_AssetManager.h>
23 #include <linux/capability.h>
25 #include <sys/types.h>
28 #include <private/android_filesystem_config.h> // for AID_SYSTEM
30 #include "androidfw/Asset.h"
31 #include "androidfw/AssetManager.h"
32 #include "androidfw/AttributeFinder.h"
33 #include "androidfw/ResourceTypes.h"
34 #include "android_runtime/AndroidRuntime.h"
35 #include "android_util_Binder.h"
36 #include "core_jni_helpers.h"
39 #include "ScopedStringChars.h"
40 #include "ScopedUtfChars.h"
41 #include "utils/Log.h"
42 #include "utils/misc.h"
44 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
45 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
50 static const bool kThrowOnBadId = false;
51 static const bool kDebugStyles = false;
53 // ----------------------------------------------------------------------------
55 static struct typedvalue_offsets_t
60 jfieldID mAssetCookie;
62 jfieldID mChangingConfigurations;
66 static struct assetfiledescriptor_offsets_t
69 jfieldID mStartOffset;
71 } gAssetFileDescriptorOffsets;
73 static struct assetmanager_offsets_t
76 } gAssetManagerOffsets;
78 static struct sparsearray_offsets_t
81 jmethodID constructor;
83 } gSparseArrayOffsets;
85 jclass g_stringClass = NULL;
87 // ----------------------------------------------------------------------------
90 STYLE_NUM_ENTRIES = 6,
93 STYLE_ASSET_COOKIE = 2,
94 STYLE_RESOURCE_ID = 3,
95 STYLE_CHANGING_CONFIGURATIONS = 4,
99 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
100 const Res_value& value, uint32_t ref, ssize_t block,
101 uint32_t typeSpecFlags, ResTable_config* config = NULL);
103 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
104 const Res_value& value, uint32_t ref, ssize_t block,
105 uint32_t typeSpecFlags, ResTable_config* config)
107 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
108 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
109 static_cast<jint>(table->getTableCookie(block)));
110 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
111 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
112 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
113 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
115 if (config != NULL) {
116 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
121 // This is called by zygote (running as user root) as part of preloadResources.
122 static void verifySystemIdmaps()
127 snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
129 switch (pid = fork()) {
131 ALOGE("failed to fork for idmap: %s", strerror(errno));
135 struct __user_cap_header_struct capheader;
136 struct __user_cap_data_struct capdata;
138 memset(&capheader, 0, sizeof(capheader));
139 memset(&capdata, 0, sizeof(capdata));
141 capheader.version = _LINUX_CAPABILITY_VERSION;
144 if (capget(&capheader, &capdata) != 0) {
145 ALOGE("capget: %s\n", strerror(errno));
149 capdata.effective = capdata.permitted;
150 if (capset(&capheader, &capdata) != 0) {
151 ALOGE("capset: %s\n", strerror(errno));
155 if (setgid(AID_SYSTEM) != 0) {
156 ALOGE("setgid: %s\n", strerror(errno));
160 if (setuid(AID_SYSTEM) != 0) {
161 ALOGE("setuid: %s\n", strerror(errno));
165 execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
166 AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
167 AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
168 ALOGE("failed to execl for idmap: %s", strerror(errno));
169 exit(1); // should never get here
173 waitpid(pid, NULL, 0);
178 // ----------------------------------------------------------------------------
180 // this guy is exported to other jni routines
181 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
183 jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
184 AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
188 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
192 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
193 jstring fileName, jint mode)
195 AssetManager* am = assetManagerForJavaObject(env, clazz);
200 ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
202 ScopedUtfChars fileName8(env, fileName);
203 if (fileName8.c_str() == NULL) {
204 jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
208 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
209 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
210 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
214 Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
217 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
221 //printf("Created Asset Stream: %p\n", a);
223 return reinterpret_cast<jlong>(a);
226 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
228 off64_t startOffset, length;
229 int fd = a->openFileDescriptor(&startOffset, &length);
233 jniThrowException(env, "java/io/FileNotFoundException",
234 "This file can not be opened as a file descriptor; it is probably compressed");
238 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
239 if (offsets == NULL) {
244 offsets[0] = startOffset;
247 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
249 jobject fileDesc = jniCreateFileDescriptor(env, fd);
250 if (fileDesc == NULL) {
255 return newParcelFileDescriptor(env, fileDesc);
258 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
259 jstring fileName, jlongArray outOffsets)
261 AssetManager* am = assetManagerForJavaObject(env, clazz);
266 ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
268 ScopedUtfChars fileName8(env, fileName);
269 if (fileName8.c_str() == NULL) {
273 Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
276 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
280 //printf("Created Asset Stream: %p\n", a);
282 return returnParcelFileDescriptor(env, a, outOffsets);
285 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
290 AssetManager* am = assetManagerForJavaObject(env, clazz);
295 ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
297 ScopedUtfChars fileName8(env, fileName);
298 if (fileName8.c_str() == NULL) {
302 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
303 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
304 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
309 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
310 (Asset::AccessMode)mode)
311 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
314 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
318 //printf("Created Asset Stream: %p\n", a);
320 return reinterpret_cast<jlong>(a);
323 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
326 jlongArray outOffsets)
328 AssetManager* am = assetManagerForJavaObject(env, clazz);
333 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
335 ScopedUtfChars fileName8(env, fileName);
336 if (fileName8.c_str() == NULL) {
341 ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
342 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
345 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
349 //printf("Created Asset Stream: %p\n", a);
351 return returnParcelFileDescriptor(env, a, outOffsets);
354 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
357 AssetManager* am = assetManagerForJavaObject(env, clazz);
362 ScopedUtfChars fileName8(env, fileName);
363 if (fileName8.c_str() == NULL) {
367 AssetDir* dir = am->openDir(fileName8.c_str());
370 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
374 size_t N = dir->getFileCount();
376 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
377 g_stringClass, NULL);
383 for (size_t i=0; i<N; i++) {
384 const String8& name = dir->getFileName(i);
385 jstring str = env->NewStringUTF(name.string());
390 env->SetObjectArrayElement(array, i, str);
391 env->DeleteLocalRef(str);
399 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
402 Asset* a = reinterpret_cast<Asset*>(assetHandle);
404 //printf("Destroying Asset Stream: %p\n", a);
407 jniThrowNullPointerException(env, "asset");
414 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
417 Asset* a = reinterpret_cast<Asset*>(assetHandle);
420 jniThrowNullPointerException(env, "asset");
425 ssize_t res = a->read(&b, 1);
426 return res == 1 ? b : -1;
429 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
430 jlong assetHandle, jbyteArray bArray,
433 Asset* a = reinterpret_cast<Asset*>(assetHandle);
435 if (a == NULL || bArray == NULL) {
436 jniThrowNullPointerException(env, "asset");
444 jsize bLen = env->GetArrayLength(bArray);
445 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
446 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
450 jbyte* b = env->GetByteArrayElements(bArray, NULL);
451 ssize_t res = a->read(b+off, len);
452 env->ReleaseByteArrayElements(bArray, b, 0);
454 if (res > 0) return static_cast<jint>(res);
457 jniThrowException(env, "java/io/IOException", "");
462 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
464 jlong offset, jint whence)
466 Asset* a = reinterpret_cast<Asset*>(assetHandle);
469 jniThrowNullPointerException(env, "asset");
474 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
477 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
480 Asset* a = reinterpret_cast<Asset*>(assetHandle);
483 jniThrowNullPointerException(env, "asset");
487 return a->getLength();
490 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
493 Asset* a = reinterpret_cast<Asset*>(assetHandle);
496 jniThrowNullPointerException(env, "asset");
500 return a->getRemainingLength();
503 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
506 ScopedUtfChars path8(env, path);
507 if (path8.c_str() == NULL) {
511 AssetManager* am = assetManagerForJavaObject(env, clazz);
517 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
519 return (res) ? static_cast<jint>(cookie) : 0;
522 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
525 ScopedUtfChars idmapPath8(env, idmapPath);
526 if (idmapPath8.c_str() == NULL) {
530 AssetManager* am = assetManagerForJavaObject(env, clazz);
536 bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
538 return (res) ? (jint)cookie : 0;
541 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
543 AssetManager* am = assetManagerForJavaObject(env, clazz);
547 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
550 static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
553 ScopedUtfChars locale8(env, locale);
554 if (locale8.c_str() == NULL) {
558 AssetManager* am = assetManagerForJavaObject(env, clazz);
563 am->setLocale(locale8.c_str());
566 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
568 Vector<String8> locales;
570 AssetManager* am = assetManagerForJavaObject(env, clazz);
575 am->getLocales(&locales);
577 const int N = locales.size();
579 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
580 if (result == NULL) {
584 for (int i=0; i<N; i++) {
585 jstring str = env->NewStringUTF(locales[i].string());
589 env->SetObjectArrayElement(result, i, str);
590 env->DeleteLocalRef(str);
596 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
598 jstring locale, jint orientation,
599 jint touchscreen, jint density,
600 jint keyboard, jint keyboardHidden,
602 jint screenWidth, jint screenHeight,
603 jint smallestScreenWidthDp,
604 jint screenWidthDp, jint screenHeightDp,
605 jint screenLayout, jint uiMode,
608 AssetManager* am = assetManagerForJavaObject(env, clazz);
613 ResTable_config config;
614 memset(&config, 0, sizeof(config));
616 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
618 config.mcc = (uint16_t)mcc;
619 config.mnc = (uint16_t)mnc;
620 config.orientation = (uint8_t)orientation;
621 config.touchscreen = (uint8_t)touchscreen;
622 config.density = (uint16_t)density;
623 config.keyboard = (uint8_t)keyboard;
624 config.inputFlags = (uint8_t)keyboardHidden;
625 config.navigation = (uint8_t)navigation;
626 config.screenWidth = (uint16_t)screenWidth;
627 config.screenHeight = (uint16_t)screenHeight;
628 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
629 config.screenWidthDp = (uint16_t)screenWidthDp;
630 config.screenHeightDp = (uint16_t)screenHeightDp;
631 config.screenLayout = (uint8_t)screenLayout;
632 config.uiMode = (uint8_t)uiMode;
633 config.sdkVersion = (uint16_t)sdkVersion;
634 config.minorVersion = 0;
635 am->setConfiguration(config, locale8);
637 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
640 static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
645 ScopedStringChars name16(env, name);
646 if (name16.get() == NULL) {
650 AssetManager* am = assetManagerForJavaObject(env, clazz);
655 const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
656 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
658 jsize defTypeLen = defType
659 ? env->GetStringLength(defType) : 0;
660 const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
661 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
664 jsize defPackageLen = defPackage
665 ? env->GetStringLength(defPackage) : 0;
667 jint ident = am->getResources().identifierForName(
668 reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
669 defType16, defTypeLen, defPackage16, defPackageLen);
672 env->ReleaseStringChars(defPackage,
673 reinterpret_cast<const jchar*>(defPackage16));
676 env->ReleaseStringChars(defType,
677 reinterpret_cast<const jchar*>(defType16));
683 static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
686 AssetManager* am = assetManagerForJavaObject(env, clazz);
691 ResTable::resource_name name;
692 if (!am->getResources().getResourceName(resid, true, &name)) {
697 if (name.package != NULL) {
698 str.setTo(name.package, name.packageLen);
700 if (name.type8 != NULL || name.type != NULL) {
701 if (str.size() > 0) {
705 if (name.type8 != NULL) {
706 str.append(String16(name.type8, name.typeLen));
708 str.append(name.type, name.typeLen);
711 if (name.name8 != NULL || name.name != NULL) {
712 if (str.size() > 0) {
716 if (name.name8 != NULL) {
717 str.append(String16(name.name8, name.nameLen));
719 str.append(name.name, name.nameLen);
723 return env->NewString((const jchar*)str.string(), str.size());
726 static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
729 AssetManager* am = assetManagerForJavaObject(env, clazz);
734 ResTable::resource_name name;
735 if (!am->getResources().getResourceName(resid, true, &name)) {
739 if (name.package != NULL) {
740 return env->NewString((const jchar*)name.package, name.packageLen);
746 static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
749 AssetManager* am = assetManagerForJavaObject(env, clazz);
754 ResTable::resource_name name;
755 if (!am->getResources().getResourceName(resid, true, &name)) {
759 if (name.type8 != NULL) {
760 return env->NewStringUTF(name.type8);
763 if (name.type != NULL) {
764 return env->NewString((const jchar*)name.type, name.typeLen);
770 static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
773 AssetManager* am = assetManagerForJavaObject(env, clazz);
778 ResTable::resource_name name;
779 if (!am->getResources().getResourceName(resid, true, &name)) {
783 if (name.name8 != NULL) {
784 return env->NewStringUTF(name.name8);
787 if (name.name != NULL) {
788 return env->NewString((const jchar*)name.name, name.nameLen);
794 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
800 if (outValue == NULL) {
801 jniThrowNullPointerException(env, "outValue");
804 AssetManager* am = assetManagerForJavaObject(env, clazz);
808 const ResTable& res(am->getResources());
811 ResTable_config config;
812 uint32_t typeSpecFlags;
813 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
815 if (block == BAD_INDEX) {
816 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
820 uint32_t ref = ident;
822 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
824 if (block == BAD_INDEX) {
825 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
831 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
834 return static_cast<jint>(block);
837 static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
838 jint ident, jint bagEntryId,
839 jobject outValue, jboolean resolve)
841 AssetManager* am = assetManagerForJavaObject(env, clazz);
845 const ResTable& res(am->getResources());
847 // Now lock down the resource object and start pulling stuff from it.
853 const ResTable::bag_entry* entry = NULL;
854 uint32_t typeSpecFlags;
855 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
857 for (ssize_t i=0; i<entryCount; i++) {
858 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
859 block = entry->stringBlock;
860 value = entry->map.value;
868 return static_cast<jint>(block);
871 uint32_t ref = ident;
873 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
875 if (block == BAD_INDEX) {
876 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
882 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
885 return static_cast<jint>(block);
888 static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
890 AssetManager* am = assetManagerForJavaObject(env, clazz);
894 return am->getResources().getTableCount();
897 static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
900 AssetManager* am = assetManagerForJavaObject(env, clazz);
904 return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
907 static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
910 AssetManager* am = assetManagerForJavaObject(env, clazz);
914 String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
915 if (name.length() == 0) {
916 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
919 jstring str = env->NewStringUTF(name.string());
923 static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
925 AssetManager* am = assetManagerForJavaObject(env, clazz);
930 const ResTable& res = am->getResources();
932 jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
933 gSparseArrayOffsets.constructor);
934 const size_t N = res.getBasePackageCount();
935 for (size_t i = 0; i < N; i++) {
936 const String16 name = res.getBasePackageName(i);
938 sparseArray, gSparseArrayOffsets.put,
939 static_cast<jint>(res.getBasePackageId(i)),
940 env->NewString(reinterpret_cast<const jchar*>(name.string()),
946 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
948 AssetManager* am = assetManagerForJavaObject(env, clazz);
952 return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
955 static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
958 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
962 static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
967 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
968 theme->applyStyle(styleRes, force ? true : false);
971 static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
972 jlong destHandle, jlong srcHandle)
974 ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
975 ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
979 static jint android_content_AssetManager_loadThemeAttributeValue(
980 JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
982 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
983 const ResTable& res(theme->getResTable());
986 // XXX value could be different in different configs!
987 uint32_t typeSpecFlags = 0;
988 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
991 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
993 if (block == BAD_INDEX) {
994 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
999 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
1002 static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
1003 jlong themeHandle, jint pri,
1004 jstring tag, jstring prefix)
1006 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1007 const ResTable& res(theme->getResTable());
1010 // XXX Need to use params.
1014 class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1016 XmlAttributeFinder(const ResXMLParser* parser)
1017 : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1018 , mParser(parser) {}
1020 inline uint32_t getAttribute(jsize index) const {
1021 return mParser->getAttributeNameResID(index);
1025 const ResXMLParser* mParser;
1028 class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1030 BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1031 : BackTrackingAttributeFinder(start, end) {}
1033 inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1034 return entry->map.name.ident;
1038 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1044 jintArray outValues,
1045 jintArray outIndices)
1047 if (themeToken == 0) {
1048 jniThrowNullPointerException(env, "theme token");
1051 if (attrs == NULL) {
1052 jniThrowNullPointerException(env, "attrs");
1055 if (outValues == NULL) {
1056 jniThrowNullPointerException(env, "out values");
1061 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
1062 "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
1065 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1066 const ResTable& res = theme->getResTable();
1067 ResTable_config config;
1070 const jsize NI = env->GetArrayLength(attrs);
1071 const jsize NV = env->GetArrayLength(outValues);
1072 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1073 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1077 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1082 jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1083 const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1085 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1086 jint* dest = baseDest;
1088 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1092 jint* indices = NULL;
1094 if (outIndices != NULL) {
1095 if (env->GetArrayLength(outIndices) > NI) {
1096 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1100 // Load default style from attribute, if specified...
1101 uint32_t defStyleBagTypeSetFlags = 0;
1102 if (defStyleAttr != 0) {
1104 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1105 if (value.dataType == Res_value::TYPE_REFERENCE) {
1106 defStyleRes = value.data;
1111 // Now lock down the resource object and start pulling stuff from it.
1114 // Retrieve the default style bag, if requested.
1115 const ResTable::bag_entry* defStyleStart = NULL;
1116 uint32_t defStyleTypeSetFlags = 0;
1117 ssize_t bagOff = defStyleRes != 0
1118 ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1119 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1120 const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1121 BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1123 // Now iterate through all of the attributes that the client has requested,
1124 // filling in each with whatever data we can find.
1126 uint32_t typeSetFlags;
1127 for (jsize ii=0; ii<NI; ii++) {
1128 const uint32_t curIdent = (uint32_t)src[ii];
1131 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1134 // Try to find a value for this attribute... we prioritize values
1135 // coming from, first XML attributes, then XML style, then default
1136 // style, and finally the theme.
1137 value.dataType = Res_value::TYPE_NULL;
1138 value.data = Res_value::DATA_NULL_UNDEFINED;
1142 // Retrieve the current input value if available.
1143 if (NSV > 0 && srcValues[ii] != 0) {
1145 value.dataType = Res_value::TYPE_ATTRIBUTE;
1146 value.data = srcValues[ii];
1148 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1152 if (value.dataType == Res_value::TYPE_NULL) {
1153 const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1154 if (defStyleEntry != defStyleEnd) {
1155 block = defStyleEntry->stringBlock;
1156 typeSetFlags = defStyleTypeSetFlags;
1157 value = defStyleEntry->map.value;
1159 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1165 if (value.dataType != Res_value::TYPE_NULL) {
1166 // Take care of resolving the found resource to its final value.
1167 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1168 &resid, &typeSetFlags, &config);
1169 if (newBlock >= 0) block = newBlock;
1171 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1174 // If we still don't have a value for this attribute, try to find
1176 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1177 if (newBlock >= 0) {
1179 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1181 newBlock = res.resolveReference(&value, block, &resid,
1182 &typeSetFlags, &config);
1183 if (kThrowOnBadId) {
1184 if (newBlock == BAD_INDEX) {
1185 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1189 if (newBlock >= 0) block = newBlock;
1191 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1196 // Deal with the special @null value -- it turns back to TYPE_NULL.
1197 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1199 ALOGI("-> Setting to @null!");
1201 value.dataType = Res_value::TYPE_NULL;
1202 value.data = Res_value::DATA_NULL_UNDEFINED;
1207 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1211 // Write the final value back to Java.
1212 dest[STYLE_TYPE] = value.dataType;
1213 dest[STYLE_DATA] = value.data;
1214 dest[STYLE_ASSET_COOKIE] =
1215 block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1216 dest[STYLE_RESOURCE_ID] = resid;
1217 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1218 dest[STYLE_DENSITY] = config.density;
1220 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1222 indices[indicesIdx] = ii;
1225 dest += STYLE_NUM_ENTRIES;
1230 if (indices != NULL) {
1231 indices[0] = indicesIdx;
1232 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1234 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1235 env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1236 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1241 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1245 jlong xmlParserToken,
1247 jintArray outValues,
1248 jintArray outIndices)
1250 if (themeToken == 0) {
1251 jniThrowNullPointerException(env, "theme token");
1254 if (attrs == NULL) {
1255 jniThrowNullPointerException(env, "attrs");
1258 if (outValues == NULL) {
1259 jniThrowNullPointerException(env, "out values");
1264 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
1265 "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
1269 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1270 const ResTable& res = theme->getResTable();
1271 ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1272 ResTable_config config;
1275 const jsize NI = env->GetArrayLength(attrs);
1276 const jsize NV = env->GetArrayLength(outValues);
1277 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1278 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1282 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1287 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1288 jint* dest = baseDest;
1290 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1294 jint* indices = NULL;
1296 if (outIndices != NULL) {
1297 if (env->GetArrayLength(outIndices) > NI) {
1298 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1302 // Load default style from attribute, if specified...
1303 uint32_t defStyleBagTypeSetFlags = 0;
1304 if (defStyleAttr != 0) {
1306 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1307 if (value.dataType == Res_value::TYPE_REFERENCE) {
1308 defStyleRes = value.data;
1313 // Retrieve the style class associated with the current XML tag.
1315 uint32_t styleBagTypeSetFlags = 0;
1316 if (xmlParser != NULL) {
1317 ssize_t idx = xmlParser->indexOfStyle();
1318 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1319 if (value.dataType == value.TYPE_ATTRIBUTE) {
1320 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1321 value.dataType = Res_value::TYPE_NULL;
1324 if (value.dataType == value.TYPE_REFERENCE) {
1330 // Now lock down the resource object and start pulling stuff from it.
1333 // Retrieve the default style bag, if requested.
1334 const ResTable::bag_entry* defStyleAttrStart = NULL;
1335 uint32_t defStyleTypeSetFlags = 0;
1336 ssize_t bagOff = defStyleRes != 0
1337 ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1338 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1339 const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1340 BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1342 // Retrieve the style class bag, if requested.
1343 const ResTable::bag_entry* styleAttrStart = NULL;
1344 uint32_t styleTypeSetFlags = 0;
1345 bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1346 styleTypeSetFlags |= styleBagTypeSetFlags;
1347 const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1348 BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1350 // Retrieve the XML attributes, if requested.
1351 static const ssize_t kXmlBlock = 0x10000000;
1352 XmlAttributeFinder xmlAttrFinder(xmlParser);
1353 const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1355 // Now iterate through all of the attributes that the client has requested,
1356 // filling in each with whatever data we can find.
1358 uint32_t typeSetFlags;
1359 for (jsize ii = 0; ii < NI; ii++) {
1360 const uint32_t curIdent = (uint32_t)src[ii];
1363 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1366 // Try to find a value for this attribute... we prioritize values
1367 // coming from, first XML attributes, then XML style, then default
1368 // style, and finally the theme.
1369 value.dataType = Res_value::TYPE_NULL;
1370 value.data = Res_value::DATA_NULL_UNDEFINED;
1374 // Walk through the xml attributes looking for the requested attribute.
1375 const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1376 if (xmlAttrIdx != xmlAttrEnd) {
1377 // We found the attribute we were looking for.
1379 xmlParser->getAttributeValue(xmlAttrIdx, &value);
1381 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1385 if (value.dataType == Res_value::TYPE_NULL) {
1386 // Walk through the style class values looking for the requested attribute.
1387 const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1388 if (styleAttrEntry != styleAttrEnd) {
1389 // We found the attribute we were looking for.
1390 block = styleAttrEntry->stringBlock;
1391 typeSetFlags = styleTypeSetFlags;
1392 value = styleAttrEntry->map.value;
1394 ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1399 if (value.dataType == Res_value::TYPE_NULL) {
1400 // Walk through the default style values looking for the requested attribute.
1401 const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1402 if (defStyleAttrEntry != defStyleAttrEnd) {
1403 // We found the attribute we were looking for.
1404 block = defStyleAttrEntry->stringBlock;
1405 typeSetFlags = styleTypeSetFlags;
1406 value = defStyleAttrEntry->map.value;
1408 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1414 if (value.dataType != Res_value::TYPE_NULL) {
1415 // Take care of resolving the found resource to its final value.
1416 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1417 &resid, &typeSetFlags, &config);
1418 if (newBlock >= 0) {
1423 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1426 // If we still don't have a value for this attribute, try to find
1428 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1429 if (newBlock >= 0) {
1431 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1433 newBlock = res.resolveReference(&value, block, &resid,
1434 &typeSetFlags, &config);
1435 if (kThrowOnBadId) {
1436 if (newBlock == BAD_INDEX) {
1437 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1442 if (newBlock >= 0) {
1447 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1452 // Deal with the special @null value -- it turns back to TYPE_NULL.
1453 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1455 ALOGI("-> Setting to @null!");
1457 value.dataType = Res_value::TYPE_NULL;
1458 value.data = Res_value::DATA_NULL_UNDEFINED;
1463 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1466 // Write the final value back to Java.
1467 dest[STYLE_TYPE] = value.dataType;
1468 dest[STYLE_DATA] = value.data;
1469 dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1470 static_cast<jint>(res.getTableCookie(block)) : -1;
1471 dest[STYLE_RESOURCE_ID] = resid;
1472 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1473 dest[STYLE_DENSITY] = config.density;
1475 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1477 indices[indicesIdx] = ii;
1480 dest += STYLE_NUM_ENTRIES;
1485 if (indices != NULL) {
1486 indices[0] = indicesIdx;
1487 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1489 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1490 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1495 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1496 jlong xmlParserToken,
1498 jintArray outValues,
1499 jintArray outIndices)
1501 if (xmlParserToken == 0) {
1502 jniThrowNullPointerException(env, "xmlParserToken");
1505 if (attrs == NULL) {
1506 jniThrowNullPointerException(env, "attrs");
1509 if (outValues == NULL) {
1510 jniThrowNullPointerException(env, "out values");
1514 AssetManager* am = assetManagerForJavaObject(env, clazz);
1518 const ResTable& res(am->getResources());
1519 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1520 ResTable_config config;
1523 const jsize NI = env->GetArrayLength(attrs);
1524 const jsize NV = env->GetArrayLength(outValues);
1525 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1526 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1530 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1535 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1536 jint* dest = baseDest;
1538 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1542 jint* indices = NULL;
1544 if (outIndices != NULL) {
1545 if (env->GetArrayLength(outIndices) > NI) {
1546 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1550 // Now lock down the resource object and start pulling stuff from it.
1553 // Retrieve the XML attributes, if requested.
1554 const jsize NX = xmlParser->getAttributeCount();
1556 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1558 static const ssize_t kXmlBlock = 0x10000000;
1560 // Now iterate through all of the attributes that the client has requested,
1561 // filling in each with whatever data we can find.
1563 uint32_t typeSetFlags;
1564 for (jsize ii=0; ii<NI; ii++) {
1565 const uint32_t curIdent = (uint32_t)src[ii];
1567 // Try to find a value for this attribute...
1568 value.dataType = Res_value::TYPE_NULL;
1569 value.data = Res_value::DATA_NULL_UNDEFINED;
1573 // Skip through XML attributes until the end or the next possible match.
1574 while (ix < NX && curIdent > curXmlAttr) {
1576 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1578 // Retrieve the current XML attribute if it matches, and step to next.
1579 if (ix < NX && curIdent == curXmlAttr) {
1581 xmlParser->getAttributeValue(ix, &value);
1583 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1586 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1588 if (value.dataType != Res_value::TYPE_NULL) {
1589 // Take care of resolving the found resource to its final value.
1590 //printf("Resolving attribute reference\n");
1591 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1592 &typeSetFlags, &config);
1593 if (kThrowOnBadId) {
1594 if (newBlock == BAD_INDEX) {
1595 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1599 if (newBlock >= 0) block = newBlock;
1602 // Deal with the special @null value -- it turns back to TYPE_NULL.
1603 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1604 value.dataType = Res_value::TYPE_NULL;
1605 value.data = Res_value::DATA_NULL_UNDEFINED;
1608 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1610 // Write the final value back to Java.
1611 dest[STYLE_TYPE] = value.dataType;
1612 dest[STYLE_DATA] = value.data;
1613 dest[STYLE_ASSET_COOKIE] =
1614 block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1615 dest[STYLE_RESOURCE_ID] = resid;
1616 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1617 dest[STYLE_DENSITY] = config.density;
1619 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1621 indices[indicesIdx] = ii;
1624 dest += STYLE_NUM_ENTRIES;
1629 if (indices != NULL) {
1630 indices[0] = indicesIdx;
1631 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1634 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1635 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1640 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1643 AssetManager* am = assetManagerForJavaObject(env, clazz);
1647 const ResTable& res(am->getResources());
1650 const ResTable::bag_entry* defStyleEnt = NULL;
1651 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1654 return static_cast<jint>(bagOff);
1657 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1659 jintArray outValues)
1661 if (outValues == NULL) {
1662 jniThrowNullPointerException(env, "out values");
1666 AssetManager* am = assetManagerForJavaObject(env, clazz);
1670 const ResTable& res(am->getResources());
1671 ResTable_config config;
1675 const jsize NV = env->GetArrayLength(outValues);
1677 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1678 jint* dest = baseDest;
1680 jniThrowException(env, "java/lang/OutOfMemoryError", "");
1684 // Now lock down the resource object and start pulling stuff from it.
1687 const ResTable::bag_entry* arrayEnt = NULL;
1688 uint32_t arrayTypeSetFlags = 0;
1689 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1690 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1691 (bagOff >= 0 ? bagOff : 0);
1694 uint32_t typeSetFlags;
1695 while (i < NV && arrayEnt < endArrayEnt) {
1696 block = arrayEnt->stringBlock;
1697 typeSetFlags = arrayTypeSetFlags;
1699 value = arrayEnt->map.value;
1702 if (value.dataType != Res_value::TYPE_NULL) {
1703 // Take care of resolving the found resource to its final value.
1704 //printf("Resolving attribute reference\n");
1705 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1706 &typeSetFlags, &config);
1707 if (kThrowOnBadId) {
1708 if (newBlock == BAD_INDEX) {
1709 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1713 if (newBlock >= 0) block = newBlock;
1716 // Deal with the special @null value -- it turns back to TYPE_NULL.
1717 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1718 value.dataType = Res_value::TYPE_NULL;
1719 value.data = Res_value::DATA_NULL_UNDEFINED;
1722 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1724 // Write the final value back to Java.
1725 dest[STYLE_TYPE] = value.dataType;
1726 dest[STYLE_DATA] = value.data;
1727 dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1728 dest[STYLE_RESOURCE_ID] = resid;
1729 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1730 dest[STYLE_DENSITY] = config.density;
1731 dest += STYLE_NUM_ENTRIES;
1732 i+= STYLE_NUM_ENTRIES;
1736 i /= STYLE_NUM_ENTRIES;
1740 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1745 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1749 AssetManager* am = assetManagerForJavaObject(env, clazz);
1754 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1756 ScopedUtfChars fileName8(env, fileName);
1757 if (fileName8.c_str() == NULL) {
1761 int32_t assetCookie = static_cast<int32_t>(cookie);
1762 Asset* a = assetCookie
1763 ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1764 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1767 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1771 const DynamicRefTable* dynamicRefTable =
1772 am->getResources().getDynamicRefTableForCookie(assetCookie);
1773 ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1774 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1778 if (err != NO_ERROR) {
1779 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1783 return reinterpret_cast<jlong>(block);
1786 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1789 AssetManager* am = assetManagerForJavaObject(env, clazz);
1793 const ResTable& res(am->getResources());
1795 const ResTable::bag_entry* startOfBag;
1796 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1801 jintArray array = env->NewIntArray(N * 2);
1802 if (array == NULL) {
1803 res.unlockBag(startOfBag);
1808 const ResTable::bag_entry* bag = startOfBag;
1809 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1810 jint stringIndex = -1;
1811 jint stringBlock = 0;
1812 value = bag->map.value;
1814 // Take care of resolving the found resource to its final value.
1815 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1816 if (value.dataType == Res_value::TYPE_STRING) {
1817 stringIndex = value.data;
1820 if (kThrowOnBadId) {
1821 if (stringBlock == BAD_INDEX) {
1822 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1827 //todo: It might be faster to allocate a C array to contain
1828 // the blocknums and indices, put them in there and then
1829 // do just one SetIntArrayRegion()
1830 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1831 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1834 res.unlockBag(startOfBag);
1838 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1841 AssetManager* am = assetManagerForJavaObject(env, clazz);
1845 const ResTable& res(am->getResources());
1847 const ResTable::bag_entry* startOfBag;
1848 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1853 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1854 if (env->ExceptionCheck()) {
1855 res.unlockBag(startOfBag);
1860 const ResTable::bag_entry* bag = startOfBag;
1862 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1863 value = bag->map.value;
1866 // Take care of resolving the found resource to its final value.
1867 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1868 if (kThrowOnBadId) {
1869 if (block == BAD_INDEX) {
1870 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1874 if (value.dataType == Res_value::TYPE_STRING) {
1875 const ResStringPool* pool = res.getTableStringBlock(block);
1876 const char* str8 = pool->string8At(value.data, &strLen);
1878 str = env->NewStringUTF(str8);
1880 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1881 str = env->NewString(reinterpret_cast<const jchar*>(str16),
1885 // If one of our NewString{UTF} calls failed due to memory, an
1886 // exception will be pending.
1887 if (env->ExceptionCheck()) {
1888 res.unlockBag(startOfBag);
1892 env->SetObjectArrayElement(array, i, str);
1894 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1895 // If we have a large amount of strings in our array, we might
1896 // overflow the local reference table of the VM.
1897 env->DeleteLocalRef(str);
1900 res.unlockBag(startOfBag);
1904 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1907 AssetManager* am = assetManagerForJavaObject(env, clazz);
1911 const ResTable& res(am->getResources());
1913 const ResTable::bag_entry* startOfBag;
1914 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1919 jintArray array = env->NewIntArray(N);
1920 if (array == NULL) {
1921 res.unlockBag(startOfBag);
1926 const ResTable::bag_entry* bag = startOfBag;
1927 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1928 value = bag->map.value;
1930 // Take care of resolving the found resource to its final value.
1931 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1932 if (kThrowOnBadId) {
1933 if (block == BAD_INDEX) {
1934 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1938 if (value.dataType >= Res_value::TYPE_FIRST_INT
1939 && value.dataType <= Res_value::TYPE_LAST_INT) {
1940 int intVal = value.data;
1941 env->SetIntArrayRegion(array, i, 1, &intVal);
1944 res.unlockBag(startOfBag);
1948 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1951 AssetManager* am = assetManagerForJavaObject(env, clazz);
1955 const ResTable& res(am->getResources());
1957 const ResTable::bag_entry* startOfBag;
1958 const ssize_t N = res.lockBag(styleId, &startOfBag);
1963 jintArray array = env->NewIntArray(N);
1964 if (array == NULL) {
1965 res.unlockBag(startOfBag);
1969 const ResTable::bag_entry* bag = startOfBag;
1970 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1971 int resourceId = bag->map.name.ident;
1972 env->SetIntArrayRegion(array, i, 1, &resourceId);
1974 res.unlockBag(startOfBag);
1978 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1981 verifySystemIdmaps();
1983 AssetManager* am = new AssetManager();
1985 jniThrowException(env, "java/lang/OutOfMemoryError", "");
1989 am->addDefaultAssets();
1991 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1992 env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1995 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1997 AssetManager* am = (AssetManager*)
1998 (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1999 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
2002 env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
2006 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2008 return Asset::getGlobalCount();
2011 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2013 String8 alloc = Asset::getAssetAllocations();
2014 if (alloc.length() <= 0) {
2018 jstring str = env->NewStringUTF(alloc.string());
2022 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2024 return AssetManager::getGlobalCount();
2027 // ----------------------------------------------------------------------------
2032 static JNINativeMethod gAssetManagerMethods[] = {
2033 /* name, signature, funcPtr */
2035 // Basic asset stuff.
2036 { "openAsset", "(Ljava/lang/String;I)J",
2037 (void*) android_content_AssetManager_openAsset },
2038 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2039 (void*) android_content_AssetManager_openAssetFd },
2040 { "openNonAssetNative", "(ILjava/lang/String;I)J",
2041 (void*) android_content_AssetManager_openNonAssetNative },
2042 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2043 (void*) android_content_AssetManager_openNonAssetFdNative },
2044 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
2045 (void*) android_content_AssetManager_list },
2046 { "destroyAsset", "(J)V",
2047 (void*) android_content_AssetManager_destroyAsset },
2048 { "readAssetChar", "(J)I",
2049 (void*) android_content_AssetManager_readAssetChar },
2050 { "readAsset", "(J[BII)I",
2051 (void*) android_content_AssetManager_readAsset },
2052 { "seekAsset", "(JJI)J",
2053 (void*) android_content_AssetManager_seekAsset },
2054 { "getAssetLength", "(J)J",
2055 (void*) android_content_AssetManager_getAssetLength },
2056 { "getAssetRemainingLength", "(J)J",
2057 (void*) android_content_AssetManager_getAssetRemainingLength },
2058 { "addAssetPathNative", "(Ljava/lang/String;)I",
2059 (void*) android_content_AssetManager_addAssetPath },
2060 { "addOverlayPathNative", "(Ljava/lang/String;)I",
2061 (void*) android_content_AssetManager_addOverlayPath },
2062 { "isUpToDate", "()Z",
2063 (void*) android_content_AssetManager_isUpToDate },
2066 { "setLocale", "(Ljava/lang/String;)V",
2067 (void*) android_content_AssetManager_setLocale },
2068 { "getLocales", "()[Ljava/lang/String;",
2069 (void*) android_content_AssetManager_getLocales },
2070 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2071 (void*) android_content_AssetManager_setConfiguration },
2072 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2073 (void*) android_content_AssetManager_getResourceIdentifier },
2074 { "getResourceName","(I)Ljava/lang/String;",
2075 (void*) android_content_AssetManager_getResourceName },
2076 { "getResourcePackageName","(I)Ljava/lang/String;",
2077 (void*) android_content_AssetManager_getResourcePackageName },
2078 { "getResourceTypeName","(I)Ljava/lang/String;",
2079 (void*) android_content_AssetManager_getResourceTypeName },
2080 { "getResourceEntryName","(I)Ljava/lang/String;",
2081 (void*) android_content_AssetManager_getResourceEntryName },
2082 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2083 (void*) android_content_AssetManager_loadResourceValue },
2084 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2085 (void*) android_content_AssetManager_loadResourceBagValue },
2086 { "getStringBlockCount","()I",
2087 (void*) android_content_AssetManager_getStringBlockCount },
2088 { "getNativeStringBlock","(I)J",
2089 (void*) android_content_AssetManager_getNativeStringBlock },
2090 { "getCookieName","(I)Ljava/lang/String;",
2091 (void*) android_content_AssetManager_getCookieName },
2092 { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2093 (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2096 { "newTheme", "()J",
2097 (void*) android_content_AssetManager_newTheme },
2098 { "deleteTheme", "(J)V",
2099 (void*) android_content_AssetManager_deleteTheme },
2100 { "applyThemeStyle", "(JIZ)V",
2101 (void*) android_content_AssetManager_applyThemeStyle },
2102 { "copyTheme", "(JJ)V",
2103 (void*) android_content_AssetManager_copyTheme },
2104 { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2105 (void*) android_content_AssetManager_loadThemeAttributeValue },
2106 { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2107 (void*) android_content_AssetManager_dumpTheme },
2108 { "applyStyle","(JIIJ[I[I[I)Z",
2109 (void*) android_content_AssetManager_applyStyle },
2110 { "resolveAttrs","(JII[I[I[I[I)Z",
2111 (void*) android_content_AssetManager_resolveAttrs },
2112 { "retrieveAttributes","(J[I[I[I)Z",
2113 (void*) android_content_AssetManager_retrieveAttributes },
2114 { "getArraySize","(I)I",
2115 (void*) android_content_AssetManager_getArraySize },
2116 { "retrieveArray","(I[I)I",
2117 (void*) android_content_AssetManager_retrieveArray },
2120 { "openXmlAssetNative", "(ILjava/lang/String;)J",
2121 (void*) android_content_AssetManager_openXmlAssetNative },
2124 { "getArrayStringResource","(I)[Ljava/lang/String;",
2125 (void*) android_content_AssetManager_getArrayStringResource },
2126 { "getArrayStringInfo","(I)[I",
2127 (void*) android_content_AssetManager_getArrayStringInfo },
2128 { "getArrayIntResource","(I)[I",
2129 (void*) android_content_AssetManager_getArrayIntResource },
2130 { "getStyleAttributes","(I)[I",
2131 (void*) android_content_AssetManager_getStyleAttributes },
2135 (void*) android_content_AssetManager_init },
2137 (void*) android_content_AssetManager_destroy },
2138 { "getGlobalAssetCount", "()I",
2139 (void*) android_content_AssetManager_getGlobalAssetCount },
2140 { "getAssetAllocations", "()Ljava/lang/String;",
2141 (void*) android_content_AssetManager_getAssetAllocations },
2142 { "getGlobalAssetManagerCount", "()I",
2143 (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2146 int register_android_content_AssetManager(JNIEnv* env)
2148 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2149 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2150 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2151 gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2152 "Ljava/lang/CharSequence;");
2153 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2154 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2155 gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2156 "changingConfigurations", "I");
2157 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
2159 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2160 gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2161 "Landroid/os/ParcelFileDescriptor;");
2162 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2163 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
2165 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2166 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
2168 jclass stringClass = FindClassOrDie(env, "java/lang/String");
2169 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
2171 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2172 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2173 gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2175 gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2176 "(ILjava/lang/Object;)V");
2178 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2179 NELEM(gAssetManagerMethods));
2182 }; // namespace android