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 // Constants duplicated from Java class android.content.res.Configuration.
619 static const jint kScreenLayoutRoundMask = 0x300;
620 static const jint kScreenLayoutRoundShift = 8;
622 config.mcc = (uint16_t)mcc;
623 config.mnc = (uint16_t)mnc;
624 config.orientation = (uint8_t)orientation;
625 config.touchscreen = (uint8_t)touchscreen;
626 config.density = (uint16_t)density;
627 config.keyboard = (uint8_t)keyboard;
628 config.inputFlags = (uint8_t)keyboardHidden;
629 config.navigation = (uint8_t)navigation;
630 config.screenWidth = (uint16_t)screenWidth;
631 config.screenHeight = (uint16_t)screenHeight;
632 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
633 config.screenWidthDp = (uint16_t)screenWidthDp;
634 config.screenHeightDp = (uint16_t)screenHeightDp;
635 config.screenLayout = (uint8_t)screenLayout;
636 config.uiMode = (uint8_t)uiMode;
637 config.sdkVersion = (uint16_t)sdkVersion;
638 config.minorVersion = 0;
640 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
641 // in C++. We must extract the round qualifier out of the Java screenLayout and put it
642 // into screenLayout2.
643 config.screenLayout2 =
644 (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
646 am->setConfiguration(config, locale8);
648 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
651 static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
656 ScopedStringChars name16(env, name);
657 if (name16.get() == NULL) {
661 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
667 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
669 jsize defTypeLen = defType
670 ? env->GetStringLength(defType) : 0;
671 const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
672 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
675 jsize defPackageLen = defPackage
676 ? env->GetStringLength(defPackage) : 0;
678 jint ident = am->getResources().identifierForName(
679 reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
680 defType16, defTypeLen, defPackage16, defPackageLen);
683 env->ReleaseStringChars(defPackage,
684 reinterpret_cast<const jchar*>(defPackage16));
687 env->ReleaseStringChars(defType,
688 reinterpret_cast<const jchar*>(defType16));
694 static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
697 AssetManager* am = assetManagerForJavaObject(env, clazz);
702 ResTable::resource_name name;
703 if (!am->getResources().getResourceName(resid, true, &name)) {
708 if (name.package != NULL) {
709 str.setTo(name.package, name.packageLen);
711 if (name.type8 != NULL || name.type != NULL) {
712 if (str.size() > 0) {
716 if (name.type8 != NULL) {
717 str.append(String16(name.type8, name.typeLen));
719 str.append(name.type, name.typeLen);
722 if (name.name8 != NULL || name.name != NULL) {
723 if (str.size() > 0) {
727 if (name.name8 != NULL) {
728 str.append(String16(name.name8, name.nameLen));
730 str.append(name.name, name.nameLen);
734 return env->NewString((const jchar*)str.string(), str.size());
737 static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
740 AssetManager* am = assetManagerForJavaObject(env, clazz);
745 ResTable::resource_name name;
746 if (!am->getResources().getResourceName(resid, true, &name)) {
750 if (name.package != NULL) {
751 return env->NewString((const jchar*)name.package, name.packageLen);
757 static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
760 AssetManager* am = assetManagerForJavaObject(env, clazz);
765 ResTable::resource_name name;
766 if (!am->getResources().getResourceName(resid, true, &name)) {
770 if (name.type8 != NULL) {
771 return env->NewStringUTF(name.type8);
774 if (name.type != NULL) {
775 return env->NewString((const jchar*)name.type, name.typeLen);
781 static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
784 AssetManager* am = assetManagerForJavaObject(env, clazz);
789 ResTable::resource_name name;
790 if (!am->getResources().getResourceName(resid, true, &name)) {
794 if (name.name8 != NULL) {
795 return env->NewStringUTF(name.name8);
798 if (name.name != NULL) {
799 return env->NewString((const jchar*)name.name, name.nameLen);
805 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
811 if (outValue == NULL) {
812 jniThrowNullPointerException(env, "outValue");
815 AssetManager* am = assetManagerForJavaObject(env, clazz);
819 const ResTable& res(am->getResources());
822 ResTable_config config;
823 uint32_t typeSpecFlags;
824 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
826 if (block == BAD_INDEX) {
827 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
831 uint32_t ref = ident;
833 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
835 if (block == BAD_INDEX) {
836 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
842 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
845 return static_cast<jint>(block);
848 static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
849 jint ident, jint bagEntryId,
850 jobject outValue, jboolean resolve)
852 AssetManager* am = assetManagerForJavaObject(env, clazz);
856 const ResTable& res(am->getResources());
858 // Now lock down the resource object and start pulling stuff from it.
864 const ResTable::bag_entry* entry = NULL;
865 uint32_t typeSpecFlags;
866 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
868 for (ssize_t i=0; i<entryCount; i++) {
869 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
870 block = entry->stringBlock;
871 value = entry->map.value;
879 return static_cast<jint>(block);
882 uint32_t ref = ident;
884 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
886 if (block == BAD_INDEX) {
887 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
893 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
896 return static_cast<jint>(block);
899 static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
901 AssetManager* am = assetManagerForJavaObject(env, clazz);
905 return am->getResources().getTableCount();
908 static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
911 AssetManager* am = assetManagerForJavaObject(env, clazz);
915 return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
918 static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
921 AssetManager* am = assetManagerForJavaObject(env, clazz);
925 String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
926 if (name.length() == 0) {
927 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
930 jstring str = env->NewStringUTF(name.string());
934 static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
936 AssetManager* am = assetManagerForJavaObject(env, clazz);
941 const ResTable& res = am->getResources();
943 jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
944 gSparseArrayOffsets.constructor);
945 const size_t N = res.getBasePackageCount();
946 for (size_t i = 0; i < N; i++) {
947 const String16 name = res.getBasePackageName(i);
949 sparseArray, gSparseArrayOffsets.put,
950 static_cast<jint>(res.getBasePackageId(i)),
951 env->NewString(reinterpret_cast<const jchar*>(name.string()),
957 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
959 AssetManager* am = assetManagerForJavaObject(env, clazz);
963 return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
966 static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
969 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
973 static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
978 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
979 theme->applyStyle(styleRes, force ? true : false);
982 static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
983 jlong destHandle, jlong srcHandle)
985 ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
986 ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
990 static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
992 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
996 static jint android_content_AssetManager_loadThemeAttributeValue(
997 JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
999 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1000 const ResTable& res(theme->getResTable());
1003 // XXX value could be different in different configs!
1004 uint32_t typeSpecFlags = 0;
1005 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
1008 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
1009 if (kThrowOnBadId) {
1010 if (block == BAD_INDEX) {
1011 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1016 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
1019 static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
1022 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1023 return theme->getChangingConfigurations();
1026 static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
1027 jlong themeHandle, jint pri,
1028 jstring tag, jstring prefix)
1030 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1031 const ResTable& res(theme->getResTable());
1034 // XXX Need to use params.
1038 class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1040 XmlAttributeFinder(const ResXMLParser* parser)
1041 : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1042 , mParser(parser) {}
1044 inline uint32_t getAttribute(jsize index) const {
1045 return mParser->getAttributeNameResID(index);
1049 const ResXMLParser* mParser;
1052 class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1054 BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1055 : BackTrackingAttributeFinder(start, end) {}
1057 inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1058 return entry->map.name.ident;
1062 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1068 jintArray outValues,
1069 jintArray outIndices)
1071 if (themeToken == 0) {
1072 jniThrowNullPointerException(env, "theme token");
1075 if (attrs == NULL) {
1076 jniThrowNullPointerException(env, "attrs");
1079 if (outValues == NULL) {
1080 jniThrowNullPointerException(env, "out values");
1085 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
1086 "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
1089 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1090 const ResTable& res = theme->getResTable();
1091 ResTable_config config;
1094 const jsize NI = env->GetArrayLength(attrs);
1095 const jsize NV = env->GetArrayLength(outValues);
1096 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1097 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1101 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1106 jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1107 const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1109 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1110 jint* dest = baseDest;
1112 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1116 jint* indices = NULL;
1118 if (outIndices != NULL) {
1119 if (env->GetArrayLength(outIndices) > NI) {
1120 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1124 // Load default style from attribute, if specified...
1125 uint32_t defStyleBagTypeSetFlags = 0;
1126 if (defStyleAttr != 0) {
1128 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1129 if (value.dataType == Res_value::TYPE_REFERENCE) {
1130 defStyleRes = value.data;
1135 // Now lock down the resource object and start pulling stuff from it.
1138 // Retrieve the default style bag, if requested.
1139 const ResTable::bag_entry* defStyleStart = NULL;
1140 uint32_t defStyleTypeSetFlags = 0;
1141 ssize_t bagOff = defStyleRes != 0
1142 ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1143 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1144 const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1145 BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1147 // Now iterate through all of the attributes that the client has requested,
1148 // filling in each with whatever data we can find.
1150 uint32_t typeSetFlags;
1151 for (jsize ii=0; ii<NI; ii++) {
1152 const uint32_t curIdent = (uint32_t)src[ii];
1155 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1158 // Try to find a value for this attribute... we prioritize values
1159 // coming from, first XML attributes, then XML style, then default
1160 // style, and finally the theme.
1161 value.dataType = Res_value::TYPE_NULL;
1162 value.data = Res_value::DATA_NULL_UNDEFINED;
1166 // Retrieve the current input value if available.
1167 if (NSV > 0 && srcValues[ii] != 0) {
1169 value.dataType = Res_value::TYPE_ATTRIBUTE;
1170 value.data = srcValues[ii];
1172 ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1176 if (value.dataType == Res_value::TYPE_NULL) {
1177 const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1178 if (defStyleEntry != defStyleEnd) {
1179 block = defStyleEntry->stringBlock;
1180 typeSetFlags = defStyleTypeSetFlags;
1181 value = defStyleEntry->map.value;
1183 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1189 if (value.dataType != Res_value::TYPE_NULL) {
1190 // Take care of resolving the found resource to its final value.
1191 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1192 &resid, &typeSetFlags, &config);
1193 if (newBlock >= 0) block = newBlock;
1195 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1198 // If we still don't have a value for this attribute, try to find
1200 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1201 if (newBlock >= 0) {
1203 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1205 newBlock = res.resolveReference(&value, block, &resid,
1206 &typeSetFlags, &config);
1207 if (kThrowOnBadId) {
1208 if (newBlock == BAD_INDEX) {
1209 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1213 if (newBlock >= 0) block = newBlock;
1215 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1220 // Deal with the special @null value -- it turns back to TYPE_NULL.
1221 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1223 ALOGI("-> Setting to @null!");
1225 value.dataType = Res_value::TYPE_NULL;
1226 value.data = Res_value::DATA_NULL_UNDEFINED;
1231 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1235 // Write the final value back to Java.
1236 dest[STYLE_TYPE] = value.dataType;
1237 dest[STYLE_DATA] = value.data;
1238 dest[STYLE_ASSET_COOKIE] =
1239 block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1240 dest[STYLE_RESOURCE_ID] = resid;
1241 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1242 dest[STYLE_DENSITY] = config.density;
1244 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1246 indices[indicesIdx] = ii;
1249 dest += STYLE_NUM_ENTRIES;
1254 if (indices != NULL) {
1255 indices[0] = indicesIdx;
1256 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1258 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1259 env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1260 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1265 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1269 jlong xmlParserToken,
1271 jintArray outValues,
1272 jintArray outIndices)
1274 if (themeToken == 0) {
1275 jniThrowNullPointerException(env, "theme token");
1278 if (attrs == NULL) {
1279 jniThrowNullPointerException(env, "attrs");
1282 if (outValues == NULL) {
1283 jniThrowNullPointerException(env, "out values");
1288 ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
1289 "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
1293 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1294 const ResTable& res = theme->getResTable();
1295 ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1296 ResTable_config config;
1299 const jsize NI = env->GetArrayLength(attrs);
1300 const jsize NV = env->GetArrayLength(outValues);
1301 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1302 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1306 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1311 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1312 jint* dest = baseDest;
1314 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1318 jint* indices = NULL;
1320 if (outIndices != NULL) {
1321 if (env->GetArrayLength(outIndices) > NI) {
1322 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1326 // Load default style from attribute, if specified...
1327 uint32_t defStyleBagTypeSetFlags = 0;
1328 if (defStyleAttr != 0) {
1330 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1331 if (value.dataType == Res_value::TYPE_REFERENCE) {
1332 defStyleRes = value.data;
1337 // Retrieve the style class associated with the current XML tag.
1339 uint32_t styleBagTypeSetFlags = 0;
1340 if (xmlParser != NULL) {
1341 ssize_t idx = xmlParser->indexOfStyle();
1342 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1343 if (value.dataType == value.TYPE_ATTRIBUTE) {
1344 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1345 value.dataType = Res_value::TYPE_NULL;
1348 if (value.dataType == value.TYPE_REFERENCE) {
1354 // Now lock down the resource object and start pulling stuff from it.
1357 // Retrieve the default style bag, if requested.
1358 const ResTable::bag_entry* defStyleAttrStart = NULL;
1359 uint32_t defStyleTypeSetFlags = 0;
1360 ssize_t bagOff = defStyleRes != 0
1361 ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1362 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1363 const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1364 BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1366 // Retrieve the style class bag, if requested.
1367 const ResTable::bag_entry* styleAttrStart = NULL;
1368 uint32_t styleTypeSetFlags = 0;
1369 bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1370 styleTypeSetFlags |= styleBagTypeSetFlags;
1371 const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1372 BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1374 // Retrieve the XML attributes, if requested.
1375 static const ssize_t kXmlBlock = 0x10000000;
1376 XmlAttributeFinder xmlAttrFinder(xmlParser);
1377 const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1379 // Now iterate through all of the attributes that the client has requested,
1380 // filling in each with whatever data we can find.
1382 uint32_t typeSetFlags;
1383 for (jsize ii = 0; ii < NI; ii++) {
1384 const uint32_t curIdent = (uint32_t)src[ii];
1387 ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1390 // Try to find a value for this attribute... we prioritize values
1391 // coming from, first XML attributes, then XML style, then default
1392 // style, and finally the theme.
1393 value.dataType = Res_value::TYPE_NULL;
1394 value.data = Res_value::DATA_NULL_UNDEFINED;
1398 // Walk through the xml attributes looking for the requested attribute.
1399 const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1400 if (xmlAttrIdx != xmlAttrEnd) {
1401 // We found the attribute we were looking for.
1403 xmlParser->getAttributeValue(xmlAttrIdx, &value);
1405 ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1409 if (value.dataType == Res_value::TYPE_NULL) {
1410 // Walk through the style class values looking for the requested attribute.
1411 const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1412 if (styleAttrEntry != styleAttrEnd) {
1413 // We found the attribute we were looking for.
1414 block = styleAttrEntry->stringBlock;
1415 typeSetFlags = styleTypeSetFlags;
1416 value = styleAttrEntry->map.value;
1418 ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1423 if (value.dataType == Res_value::TYPE_NULL) {
1424 // Walk through the default style values looking for the requested attribute.
1425 const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1426 if (defStyleAttrEntry != defStyleAttrEnd) {
1427 // We found the attribute we were looking for.
1428 block = defStyleAttrEntry->stringBlock;
1429 typeSetFlags = styleTypeSetFlags;
1430 value = defStyleAttrEntry->map.value;
1432 ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1438 if (value.dataType != Res_value::TYPE_NULL) {
1439 // Take care of resolving the found resource to its final value.
1440 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1441 &resid, &typeSetFlags, &config);
1442 if (newBlock >= 0) {
1447 ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1450 // If we still don't have a value for this attribute, try to find
1452 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1453 if (newBlock >= 0) {
1455 ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1457 newBlock = res.resolveReference(&value, block, &resid,
1458 &typeSetFlags, &config);
1459 if (kThrowOnBadId) {
1460 if (newBlock == BAD_INDEX) {
1461 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1466 if (newBlock >= 0) {
1471 ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1476 // Deal with the special @null value -- it turns back to TYPE_NULL.
1477 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1479 ALOGI("-> Setting to @null!");
1481 value.dataType = Res_value::TYPE_NULL;
1482 value.data = Res_value::DATA_NULL_UNDEFINED;
1487 ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1490 // Write the final value back to Java.
1491 dest[STYLE_TYPE] = value.dataType;
1492 dest[STYLE_DATA] = value.data;
1493 dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1494 static_cast<jint>(res.getTableCookie(block)) : -1;
1495 dest[STYLE_RESOURCE_ID] = resid;
1496 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1497 dest[STYLE_DENSITY] = config.density;
1499 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1501 indices[indicesIdx] = ii;
1504 dest += STYLE_NUM_ENTRIES;
1509 if (indices != NULL) {
1510 indices[0] = indicesIdx;
1511 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1513 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1514 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1519 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1520 jlong xmlParserToken,
1522 jintArray outValues,
1523 jintArray outIndices)
1525 if (xmlParserToken == 0) {
1526 jniThrowNullPointerException(env, "xmlParserToken");
1529 if (attrs == NULL) {
1530 jniThrowNullPointerException(env, "attrs");
1533 if (outValues == NULL) {
1534 jniThrowNullPointerException(env, "out values");
1538 AssetManager* am = assetManagerForJavaObject(env, clazz);
1542 const ResTable& res(am->getResources());
1543 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1544 ResTable_config config;
1547 const jsize NI = env->GetArrayLength(attrs);
1548 const jsize NV = env->GetArrayLength(outValues);
1549 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1550 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1554 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1559 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1560 jint* dest = baseDest;
1562 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1566 jint* indices = NULL;
1568 if (outIndices != NULL) {
1569 if (env->GetArrayLength(outIndices) > NI) {
1570 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1574 // Now lock down the resource object and start pulling stuff from it.
1577 // Retrieve the XML attributes, if requested.
1578 const jsize NX = xmlParser->getAttributeCount();
1580 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1582 static const ssize_t kXmlBlock = 0x10000000;
1584 // Now iterate through all of the attributes that the client has requested,
1585 // filling in each with whatever data we can find.
1587 uint32_t typeSetFlags;
1588 for (jsize ii=0; ii<NI; ii++) {
1589 const uint32_t curIdent = (uint32_t)src[ii];
1591 // Try to find a value for this attribute...
1592 value.dataType = Res_value::TYPE_NULL;
1593 value.data = Res_value::DATA_NULL_UNDEFINED;
1597 // Skip through XML attributes until the end or the next possible match.
1598 while (ix < NX && curIdent > curXmlAttr) {
1600 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1602 // Retrieve the current XML attribute if it matches, and step to next.
1603 if (ix < NX && curIdent == curXmlAttr) {
1605 xmlParser->getAttributeValue(ix, &value);
1607 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1610 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1612 if (value.dataType != Res_value::TYPE_NULL) {
1613 // Take care of resolving the found resource to its final value.
1614 //printf("Resolving attribute reference\n");
1615 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1616 &typeSetFlags, &config);
1617 if (kThrowOnBadId) {
1618 if (newBlock == BAD_INDEX) {
1619 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1623 if (newBlock >= 0) block = newBlock;
1626 // Deal with the special @null value -- it turns back to TYPE_NULL.
1627 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1628 value.dataType = Res_value::TYPE_NULL;
1629 value.data = Res_value::DATA_NULL_UNDEFINED;
1632 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1634 // Write the final value back to Java.
1635 dest[STYLE_TYPE] = value.dataType;
1636 dest[STYLE_DATA] = value.data;
1637 dest[STYLE_ASSET_COOKIE] =
1638 block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1639 dest[STYLE_RESOURCE_ID] = resid;
1640 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1641 dest[STYLE_DENSITY] = config.density;
1643 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1645 indices[indicesIdx] = ii;
1648 dest += STYLE_NUM_ENTRIES;
1653 if (indices != NULL) {
1654 indices[0] = indicesIdx;
1655 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1658 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1659 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1664 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1667 AssetManager* am = assetManagerForJavaObject(env, clazz);
1671 const ResTable& res(am->getResources());
1674 const ResTable::bag_entry* defStyleEnt = NULL;
1675 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1678 return static_cast<jint>(bagOff);
1681 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1683 jintArray outValues)
1685 if (outValues == NULL) {
1686 jniThrowNullPointerException(env, "out values");
1690 AssetManager* am = assetManagerForJavaObject(env, clazz);
1694 const ResTable& res(am->getResources());
1695 ResTable_config config;
1699 const jsize NV = env->GetArrayLength(outValues);
1701 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1702 jint* dest = baseDest;
1704 jniThrowException(env, "java/lang/OutOfMemoryError", "");
1708 // Now lock down the resource object and start pulling stuff from it.
1711 const ResTable::bag_entry* arrayEnt = NULL;
1712 uint32_t arrayTypeSetFlags = 0;
1713 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1714 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1715 (bagOff >= 0 ? bagOff : 0);
1718 uint32_t typeSetFlags;
1719 while (i < NV && arrayEnt < endArrayEnt) {
1720 block = arrayEnt->stringBlock;
1721 typeSetFlags = arrayTypeSetFlags;
1723 value = arrayEnt->map.value;
1726 if (value.dataType != Res_value::TYPE_NULL) {
1727 // Take care of resolving the found resource to its final value.
1728 //printf("Resolving attribute reference\n");
1729 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1730 &typeSetFlags, &config);
1731 if (kThrowOnBadId) {
1732 if (newBlock == BAD_INDEX) {
1733 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1737 if (newBlock >= 0) block = newBlock;
1740 // Deal with the special @null value -- it turns back to TYPE_NULL.
1741 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1742 value.dataType = Res_value::TYPE_NULL;
1743 value.data = Res_value::DATA_NULL_UNDEFINED;
1746 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1748 // Write the final value back to Java.
1749 dest[STYLE_TYPE] = value.dataType;
1750 dest[STYLE_DATA] = value.data;
1751 dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1752 dest[STYLE_RESOURCE_ID] = resid;
1753 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1754 dest[STYLE_DENSITY] = config.density;
1755 dest += STYLE_NUM_ENTRIES;
1756 i+= STYLE_NUM_ENTRIES;
1760 i /= STYLE_NUM_ENTRIES;
1764 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1769 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1773 AssetManager* am = assetManagerForJavaObject(env, clazz);
1778 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1780 ScopedUtfChars fileName8(env, fileName);
1781 if (fileName8.c_str() == NULL) {
1785 int32_t assetCookie = static_cast<int32_t>(cookie);
1786 Asset* a = assetCookie
1787 ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1788 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1791 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1795 const DynamicRefTable* dynamicRefTable =
1796 am->getResources().getDynamicRefTableForCookie(assetCookie);
1797 ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1798 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1802 if (err != NO_ERROR) {
1803 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1807 return reinterpret_cast<jlong>(block);
1810 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1813 AssetManager* am = assetManagerForJavaObject(env, clazz);
1817 const ResTable& res(am->getResources());
1819 const ResTable::bag_entry* startOfBag;
1820 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1825 jintArray array = env->NewIntArray(N * 2);
1826 if (array == NULL) {
1827 res.unlockBag(startOfBag);
1832 const ResTable::bag_entry* bag = startOfBag;
1833 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1834 jint stringIndex = -1;
1835 jint stringBlock = 0;
1836 value = bag->map.value;
1838 // Take care of resolving the found resource to its final value.
1839 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1840 if (value.dataType == Res_value::TYPE_STRING) {
1841 stringIndex = value.data;
1844 if (kThrowOnBadId) {
1845 if (stringBlock == BAD_INDEX) {
1846 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1851 //todo: It might be faster to allocate a C array to contain
1852 // the blocknums and indices, put them in there and then
1853 // do just one SetIntArrayRegion()
1854 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1855 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1858 res.unlockBag(startOfBag);
1862 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1865 AssetManager* am = assetManagerForJavaObject(env, clazz);
1869 const ResTable& res(am->getResources());
1871 const ResTable::bag_entry* startOfBag;
1872 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1877 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1878 if (env->ExceptionCheck()) {
1879 res.unlockBag(startOfBag);
1884 const ResTable::bag_entry* bag = startOfBag;
1886 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1887 value = bag->map.value;
1890 // Take care of resolving the found resource to its final value.
1891 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1892 if (kThrowOnBadId) {
1893 if (block == BAD_INDEX) {
1894 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1898 if (value.dataType == Res_value::TYPE_STRING) {
1899 const ResStringPool* pool = res.getTableStringBlock(block);
1900 const char* str8 = pool->string8At(value.data, &strLen);
1902 str = env->NewStringUTF(str8);
1904 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1905 str = env->NewString(reinterpret_cast<const jchar*>(str16),
1909 // If one of our NewString{UTF} calls failed due to memory, an
1910 // exception will be pending.
1911 if (env->ExceptionCheck()) {
1912 res.unlockBag(startOfBag);
1916 env->SetObjectArrayElement(array, i, str);
1918 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1919 // If we have a large amount of strings in our array, we might
1920 // overflow the local reference table of the VM.
1921 env->DeleteLocalRef(str);
1924 res.unlockBag(startOfBag);
1928 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1931 AssetManager* am = assetManagerForJavaObject(env, clazz);
1935 const ResTable& res(am->getResources());
1937 const ResTable::bag_entry* startOfBag;
1938 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1943 jintArray array = env->NewIntArray(N);
1944 if (array == NULL) {
1945 res.unlockBag(startOfBag);
1950 const ResTable::bag_entry* bag = startOfBag;
1951 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1952 value = bag->map.value;
1954 // Take care of resolving the found resource to its final value.
1955 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1956 if (kThrowOnBadId) {
1957 if (block == BAD_INDEX) {
1958 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1962 if (value.dataType >= Res_value::TYPE_FIRST_INT
1963 && value.dataType <= Res_value::TYPE_LAST_INT) {
1964 int intVal = value.data;
1965 env->SetIntArrayRegion(array, i, 1, &intVal);
1968 res.unlockBag(startOfBag);
1972 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1975 AssetManager* am = assetManagerForJavaObject(env, clazz);
1979 const ResTable& res(am->getResources());
1981 const ResTable::bag_entry* startOfBag;
1982 const ssize_t N = res.lockBag(styleId, &startOfBag);
1987 jintArray array = env->NewIntArray(N);
1988 if (array == NULL) {
1989 res.unlockBag(startOfBag);
1993 const ResTable::bag_entry* bag = startOfBag;
1994 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1995 int resourceId = bag->map.name.ident;
1996 env->SetIntArrayRegion(array, i, 1, &resourceId);
1998 res.unlockBag(startOfBag);
2002 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
2005 verifySystemIdmaps();
2007 AssetManager* am = new AssetManager();
2009 jniThrowException(env, "java/lang/OutOfMemoryError", "");
2013 am->addDefaultAssets();
2015 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
2016 env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
2019 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
2021 AssetManager* am = (AssetManager*)
2022 (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
2023 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
2026 env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
2030 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2032 return Asset::getGlobalCount();
2035 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2037 String8 alloc = Asset::getAssetAllocations();
2038 if (alloc.length() <= 0) {
2042 jstring str = env->NewStringUTF(alloc.string());
2046 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2048 return AssetManager::getGlobalCount();
2051 // ----------------------------------------------------------------------------
2056 static JNINativeMethod gAssetManagerMethods[] = {
2057 /* name, signature, funcPtr */
2059 // Basic asset stuff.
2060 { "openAsset", "(Ljava/lang/String;I)J",
2061 (void*) android_content_AssetManager_openAsset },
2062 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2063 (void*) android_content_AssetManager_openAssetFd },
2064 { "openNonAssetNative", "(ILjava/lang/String;I)J",
2065 (void*) android_content_AssetManager_openNonAssetNative },
2066 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2067 (void*) android_content_AssetManager_openNonAssetFdNative },
2068 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
2069 (void*) android_content_AssetManager_list },
2070 { "destroyAsset", "(J)V",
2071 (void*) android_content_AssetManager_destroyAsset },
2072 { "readAssetChar", "(J)I",
2073 (void*) android_content_AssetManager_readAssetChar },
2074 { "readAsset", "(J[BII)I",
2075 (void*) android_content_AssetManager_readAsset },
2076 { "seekAsset", "(JJI)J",
2077 (void*) android_content_AssetManager_seekAsset },
2078 { "getAssetLength", "(J)J",
2079 (void*) android_content_AssetManager_getAssetLength },
2080 { "getAssetRemainingLength", "(J)J",
2081 (void*) android_content_AssetManager_getAssetRemainingLength },
2082 { "addAssetPathNative", "(Ljava/lang/String;)I",
2083 (void*) android_content_AssetManager_addAssetPath },
2084 { "addOverlayPathNative", "(Ljava/lang/String;)I",
2085 (void*) android_content_AssetManager_addOverlayPath },
2086 { "isUpToDate", "()Z",
2087 (void*) android_content_AssetManager_isUpToDate },
2090 { "setLocale", "(Ljava/lang/String;)V",
2091 (void*) android_content_AssetManager_setLocale },
2092 { "getLocales", "()[Ljava/lang/String;",
2093 (void*) android_content_AssetManager_getLocales },
2094 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2095 (void*) android_content_AssetManager_setConfiguration },
2096 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2097 (void*) android_content_AssetManager_getResourceIdentifier },
2098 { "getResourceName","(I)Ljava/lang/String;",
2099 (void*) android_content_AssetManager_getResourceName },
2100 { "getResourcePackageName","(I)Ljava/lang/String;",
2101 (void*) android_content_AssetManager_getResourcePackageName },
2102 { "getResourceTypeName","(I)Ljava/lang/String;",
2103 (void*) android_content_AssetManager_getResourceTypeName },
2104 { "getResourceEntryName","(I)Ljava/lang/String;",
2105 (void*) android_content_AssetManager_getResourceEntryName },
2106 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2107 (void*) android_content_AssetManager_loadResourceValue },
2108 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2109 (void*) android_content_AssetManager_loadResourceBagValue },
2110 { "getStringBlockCount","()I",
2111 (void*) android_content_AssetManager_getStringBlockCount },
2112 { "getNativeStringBlock","(I)J",
2113 (void*) android_content_AssetManager_getNativeStringBlock },
2114 { "getCookieName","(I)Ljava/lang/String;",
2115 (void*) android_content_AssetManager_getCookieName },
2116 { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2117 (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2120 { "newTheme", "()J",
2121 (void*) android_content_AssetManager_newTheme },
2122 { "deleteTheme", "(J)V",
2123 (void*) android_content_AssetManager_deleteTheme },
2124 { "applyThemeStyle", "(JIZ)V",
2125 (void*) android_content_AssetManager_applyThemeStyle },
2126 { "copyTheme", "(JJ)V",
2127 (void*) android_content_AssetManager_copyTheme },
2128 { "clearTheme", "(J)V",
2129 (void*) android_content_AssetManager_clearTheme },
2130 { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2131 (void*) android_content_AssetManager_loadThemeAttributeValue },
2132 { "getThemeChangingConfigurations", "(J)I",
2133 (void*) android_content_AssetManager_getThemeChangingConfigurations },
2134 { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2135 (void*) android_content_AssetManager_dumpTheme },
2136 { "applyStyle","(JIIJ[I[I[I)Z",
2137 (void*) android_content_AssetManager_applyStyle },
2138 { "resolveAttrs","(JII[I[I[I[I)Z",
2139 (void*) android_content_AssetManager_resolveAttrs },
2140 { "retrieveAttributes","(J[I[I[I)Z",
2141 (void*) android_content_AssetManager_retrieveAttributes },
2142 { "getArraySize","(I)I",
2143 (void*) android_content_AssetManager_getArraySize },
2144 { "retrieveArray","(I[I)I",
2145 (void*) android_content_AssetManager_retrieveArray },
2148 { "openXmlAssetNative", "(ILjava/lang/String;)J",
2149 (void*) android_content_AssetManager_openXmlAssetNative },
2152 { "getArrayStringResource","(I)[Ljava/lang/String;",
2153 (void*) android_content_AssetManager_getArrayStringResource },
2154 { "getArrayStringInfo","(I)[I",
2155 (void*) android_content_AssetManager_getArrayStringInfo },
2156 { "getArrayIntResource","(I)[I",
2157 (void*) android_content_AssetManager_getArrayIntResource },
2158 { "getStyleAttributes","(I)[I",
2159 (void*) android_content_AssetManager_getStyleAttributes },
2163 (void*) android_content_AssetManager_init },
2165 (void*) android_content_AssetManager_destroy },
2166 { "getGlobalAssetCount", "()I",
2167 (void*) android_content_AssetManager_getGlobalAssetCount },
2168 { "getAssetAllocations", "()Ljava/lang/String;",
2169 (void*) android_content_AssetManager_getAssetAllocations },
2170 { "getGlobalAssetManagerCount", "()I",
2171 (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2174 int register_android_content_AssetManager(JNIEnv* env)
2176 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2177 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2178 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2179 gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2180 "Ljava/lang/CharSequence;");
2181 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2182 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2183 gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2184 "changingConfigurations", "I");
2185 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
2187 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2188 gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2189 "Landroid/os/ParcelFileDescriptor;");
2190 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2191 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
2193 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2194 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
2196 jclass stringClass = FindClassOrDie(env, "java/lang/String");
2197 g_stringClass = MakeGlobalRefOrDie(env, stringClass);
2199 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2200 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2201 gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2203 gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2204 "(ILjava/lang/Object;)V");
2206 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2207 NELEM(gAssetManagerMethods));
2210 }; // namespace android