Home | History | Annotate | Download | only in jni
      1 /* //device/libs/android_runtime/android_util_AssetManager.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      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
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     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.
     16 */
     17 
     18 #define LOG_TAG "asset"
     19 
     20 #define DEBUG_STYLES(x) //x
     21 #define THROW_ON_BAD_ID 0
     22 
     23 #include <android_runtime/android_util_AssetManager.h>
     24 
     25 #include "jni.h"
     26 #include "JNIHelp.h"
     27 #include "ScopedStringChars.h"
     28 #include "ScopedUtfChars.h"
     29 #include "android_util_Binder.h"
     30 #include <utils/misc.h>
     31 #include <android_runtime/AndroidRuntime.h>
     32 #include <utils/Log.h>
     33 
     34 #include <androidfw/Asset.h>
     35 #include <androidfw/AssetManager.h>
     36 #include <androidfw/ResourceTypes.h>
     37 
     38 #include <private/android_filesystem_config.h> // for AID_SYSTEM
     39 
     40 #include <stdio.h>
     41 #include <sys/types.h>
     42 #include <sys/wait.h>
     43 
     44 #include <linux/capability.h>
     45 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
     46 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
     47 
     48 
     49 namespace android {
     50 
     51 // ----------------------------------------------------------------------------
     52 
     53 static struct typedvalue_offsets_t
     54 {
     55     jfieldID mType;
     56     jfieldID mData;
     57     jfieldID mString;
     58     jfieldID mAssetCookie;
     59     jfieldID mResourceId;
     60     jfieldID mChangingConfigurations;
     61     jfieldID mDensity;
     62 } gTypedValueOffsets;
     63 
     64 static struct assetfiledescriptor_offsets_t
     65 {
     66     jfieldID mFd;
     67     jfieldID mStartOffset;
     68     jfieldID mLength;
     69 } gAssetFileDescriptorOffsets;
     70 
     71 static struct assetmanager_offsets_t
     72 {
     73     jfieldID mObject;
     74 } gAssetManagerOffsets;
     75 
     76 static struct sparsearray_offsets_t
     77 {
     78     jclass classObject;
     79     jmethodID constructor;
     80     jmethodID put;
     81 } gSparseArrayOffsets;
     82 
     83 jclass g_stringClass = NULL;
     84 
     85 // ----------------------------------------------------------------------------
     86 
     87 enum {
     88     STYLE_NUM_ENTRIES = 6,
     89     STYLE_TYPE = 0,
     90     STYLE_DATA = 1,
     91     STYLE_ASSET_COOKIE = 2,
     92     STYLE_RESOURCE_ID = 3,
     93     STYLE_CHANGING_CONFIGURATIONS = 4,
     94     STYLE_DENSITY = 5
     95 };
     96 
     97 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
     98                       const Res_value& value, uint32_t ref, ssize_t block,
     99                       uint32_t typeSpecFlags, ResTable_config* config = NULL);
    100 
    101 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
    102                const Res_value& value, uint32_t ref, ssize_t block,
    103                uint32_t typeSpecFlags, ResTable_config* config)
    104 {
    105     env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
    106     env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
    107                      static_cast<jint>(table->getTableCookie(block)));
    108     env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
    109     env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
    110     env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
    111     env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
    112             typeSpecFlags);
    113     if (config != NULL) {
    114         env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
    115     }
    116     return block;
    117 }
    118 
    119 // This is called by zygote (running as user root) as part of preloadResources.
    120 static void verifySystemIdmaps()
    121 {
    122     pid_t pid;
    123     char system_id[10];
    124 
    125     snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
    126 
    127     switch (pid = fork()) {
    128         case -1:
    129             ALOGE("failed to fork for idmap: %s", strerror(errno));
    130             break;
    131         case 0: // child
    132             {
    133                 struct __user_cap_header_struct capheader;
    134                 struct __user_cap_data_struct capdata;
    135 
    136                 memset(&capheader, 0, sizeof(capheader));
    137                 memset(&capdata, 0, sizeof(capdata));
    138 
    139                 capheader.version = _LINUX_CAPABILITY_VERSION;
    140                 capheader.pid = 0;
    141 
    142                 if (capget(&capheader, &capdata) != 0) {
    143                     ALOGE("capget: %s\n", strerror(errno));
    144                     exit(1);
    145                 }
    146 
    147                 capdata.effective = capdata.permitted;
    148                 if (capset(&capheader, &capdata) != 0) {
    149                     ALOGE("capset: %s\n", strerror(errno));
    150                     exit(1);
    151                 }
    152 
    153                 if (setgid(AID_SYSTEM) != 0) {
    154                     ALOGE("setgid: %s\n", strerror(errno));
    155                     exit(1);
    156                 }
    157 
    158                 if (setuid(AID_SYSTEM) != 0) {
    159                     ALOGE("setuid: %s\n", strerror(errno));
    160                     exit(1);
    161                 }
    162 
    163                 execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
    164                         AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
    165                         AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
    166                 ALOGE("failed to execl for idmap: %s", strerror(errno));
    167                 exit(1); // should never get here
    168             }
    169             break;
    170         default: // parent
    171             waitpid(pid, NULL, 0);
    172             break;
    173     }
    174 }
    175 
    176 // ----------------------------------------------------------------------------
    177 
    178 // this guy is exported to other jni routines
    179 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
    180 {
    181     jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
    182     AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
    183     if (am != NULL) {
    184         return am;
    185     }
    186     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
    187     return NULL;
    188 }
    189 
    190 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
    191                                                 jstring fileName, jint mode)
    192 {
    193     AssetManager* am = assetManagerForJavaObject(env, clazz);
    194     if (am == NULL) {
    195         return 0;
    196     }
    197 
    198     ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
    199 
    200     ScopedUtfChars fileName8(env, fileName);
    201     if (fileName8.c_str() == NULL) {
    202         jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
    203         return -1;
    204     }
    205 
    206     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
    207         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
    208         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    209         return -1;
    210     }
    211 
    212     Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
    213 
    214     if (a == NULL) {
    215         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    216         return -1;
    217     }
    218 
    219     //printf("Created Asset Stream: %p\n", a);
    220 
    221     return reinterpret_cast<jlong>(a);
    222 }
    223 
    224 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
    225 {
    226     off64_t startOffset, length;
    227     int fd = a->openFileDescriptor(&startOffset, &length);
    228     delete a;
    229 
    230     if (fd < 0) {
    231         jniThrowException(env, "java/io/FileNotFoundException",
    232                 "This file can not be opened as a file descriptor; it is probably compressed");
    233         return NULL;
    234     }
    235 
    236     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
    237     if (offsets == NULL) {
    238         close(fd);
    239         return NULL;
    240     }
    241 
    242     offsets[0] = startOffset;
    243     offsets[1] = length;
    244 
    245     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
    246 
    247     jobject fileDesc = jniCreateFileDescriptor(env, fd);
    248     if (fileDesc == NULL) {
    249         close(fd);
    250         return NULL;
    251     }
    252 
    253     return newParcelFileDescriptor(env, fileDesc);
    254 }
    255 
    256 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
    257                                                 jstring fileName, jlongArray outOffsets)
    258 {
    259     AssetManager* am = assetManagerForJavaObject(env, clazz);
    260     if (am == NULL) {
    261         return NULL;
    262     }
    263 
    264     ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
    265 
    266     ScopedUtfChars fileName8(env, fileName);
    267     if (fileName8.c_str() == NULL) {
    268         return NULL;
    269     }
    270 
    271     Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
    272 
    273     if (a == NULL) {
    274         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    275         return NULL;
    276     }
    277 
    278     //printf("Created Asset Stream: %p\n", a);
    279 
    280     return returnParcelFileDescriptor(env, a, outOffsets);
    281 }
    282 
    283 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
    284                                                          jint cookie,
    285                                                          jstring fileName,
    286                                                          jint mode)
    287 {
    288     AssetManager* am = assetManagerForJavaObject(env, clazz);
    289     if (am == NULL) {
    290         return 0;
    291     }
    292 
    293     ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
    294 
    295     ScopedUtfChars fileName8(env, fileName);
    296     if (fileName8.c_str() == NULL) {
    297         return -1;
    298     }
    299 
    300     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
    301         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
    302         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    303         return -1;
    304     }
    305 
    306     Asset* a = cookie
    307         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
    308                 (Asset::AccessMode)mode)
    309         : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
    310 
    311     if (a == NULL) {
    312         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    313         return -1;
    314     }
    315 
    316     //printf("Created Asset Stream: %p\n", a);
    317 
    318     return reinterpret_cast<jlong>(a);
    319 }
    320 
    321 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
    322                                                          jint cookie,
    323                                                          jstring fileName,
    324                                                          jlongArray outOffsets)
    325 {
    326     AssetManager* am = assetManagerForJavaObject(env, clazz);
    327     if (am == NULL) {
    328         return NULL;
    329     }
    330 
    331     ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
    332 
    333     ScopedUtfChars fileName8(env, fileName);
    334     if (fileName8.c_str() == NULL) {
    335         return NULL;
    336     }
    337 
    338     Asset* a = cookie
    339         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
    340         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
    341 
    342     if (a == NULL) {
    343         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    344         return NULL;
    345     }
    346 
    347     //printf("Created Asset Stream: %p\n", a);
    348 
    349     return returnParcelFileDescriptor(env, a, outOffsets);
    350 }
    351 
    352 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
    353                                                    jstring fileName)
    354 {
    355     AssetManager* am = assetManagerForJavaObject(env, clazz);
    356     if (am == NULL) {
    357         return NULL;
    358     }
    359 
    360     ScopedUtfChars fileName8(env, fileName);
    361     if (fileName8.c_str() == NULL) {
    362         return NULL;
    363     }
    364 
    365     AssetDir* dir = am->openDir(fileName8.c_str());
    366 
    367     if (dir == NULL) {
    368         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    369         return NULL;
    370     }
    371 
    372     size_t N = dir->getFileCount();
    373 
    374     jobjectArray array = env->NewObjectArray(dir->getFileCount(),
    375                                                 g_stringClass, NULL);
    376     if (array == NULL) {
    377         delete dir;
    378         return NULL;
    379     }
    380 
    381     for (size_t i=0; i<N; i++) {
    382         const String8& name = dir->getFileName(i);
    383         jstring str = env->NewStringUTF(name.string());
    384         if (str == NULL) {
    385             delete dir;
    386             return NULL;
    387         }
    388         env->SetObjectArrayElement(array, i, str);
    389         env->DeleteLocalRef(str);
    390     }
    391 
    392     delete dir;
    393 
    394     return array;
    395 }
    396 
    397 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
    398                                                       jlong assetHandle)
    399 {
    400     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    401 
    402     //printf("Destroying Asset Stream: %p\n", a);
    403 
    404     if (a == NULL) {
    405         jniThrowNullPointerException(env, "asset");
    406         return;
    407     }
    408 
    409     delete a;
    410 }
    411 
    412 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
    413                                                        jlong assetHandle)
    414 {
    415     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    416 
    417     if (a == NULL) {
    418         jniThrowNullPointerException(env, "asset");
    419         return -1;
    420     }
    421 
    422     uint8_t b;
    423     ssize_t res = a->read(&b, 1);
    424     return res == 1 ? b : -1;
    425 }
    426 
    427 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
    428                                                 jlong assetHandle, jbyteArray bArray,
    429                                                 jint off, jint len)
    430 {
    431     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    432 
    433     if (a == NULL || bArray == NULL) {
    434         jniThrowNullPointerException(env, "asset");
    435         return -1;
    436     }
    437 
    438     if (len == 0) {
    439         return 0;
    440     }
    441 
    442     jsize bLen = env->GetArrayLength(bArray);
    443     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
    444         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
    445         return -1;
    446     }
    447 
    448     jbyte* b = env->GetByteArrayElements(bArray, NULL);
    449     ssize_t res = a->read(b+off, len);
    450     env->ReleaseByteArrayElements(bArray, b, 0);
    451 
    452     if (res > 0) return static_cast<jint>(res);
    453 
    454     if (res < 0) {
    455         jniThrowException(env, "java/io/IOException", "");
    456     }
    457     return -1;
    458 }
    459 
    460 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
    461                                                  jlong assetHandle,
    462                                                  jlong offset, jint whence)
    463 {
    464     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    465 
    466     if (a == NULL) {
    467         jniThrowNullPointerException(env, "asset");
    468         return -1;
    469     }
    470 
    471     return a->seek(
    472         offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
    473 }
    474 
    475 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
    476                                                       jlong assetHandle)
    477 {
    478     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    479 
    480     if (a == NULL) {
    481         jniThrowNullPointerException(env, "asset");
    482         return -1;
    483     }
    484 
    485     return a->getLength();
    486 }
    487 
    488 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
    489                                                                jlong assetHandle)
    490 {
    491     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    492 
    493     if (a == NULL) {
    494         jniThrowNullPointerException(env, "asset");
    495         return -1;
    496     }
    497 
    498     return a->getRemainingLength();
    499 }
    500 
    501 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
    502                                                        jstring path)
    503 {
    504     ScopedUtfChars path8(env, path);
    505     if (path8.c_str() == NULL) {
    506         return 0;
    507     }
    508 
    509     AssetManager* am = assetManagerForJavaObject(env, clazz);
    510     if (am == NULL) {
    511         return 0;
    512     }
    513 
    514     int32_t cookie;
    515     bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
    516 
    517     return (res) ? static_cast<jint>(cookie) : 0;
    518 }
    519 
    520 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
    521                                                      jstring idmapPath)
    522 {
    523     ScopedUtfChars idmapPath8(env, idmapPath);
    524     if (idmapPath8.c_str() == NULL) {
    525         return 0;
    526     }
    527 
    528     AssetManager* am = assetManagerForJavaObject(env, clazz);
    529     if (am == NULL) {
    530         return 0;
    531     }
    532 
    533     int32_t cookie;
    534     bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
    535 
    536     return (res) ? (jint)cookie : 0;
    537 }
    538 
    539 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
    540 {
    541     AssetManager* am = assetManagerForJavaObject(env, clazz);
    542     if (am == NULL) {
    543         return JNI_TRUE;
    544     }
    545     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
    546 }
    547 
    548 static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
    549                                                 jstring locale)
    550 {
    551     ScopedUtfChars locale8(env, locale);
    552     if (locale8.c_str() == NULL) {
    553         return;
    554     }
    555 
    556     AssetManager* am = assetManagerForJavaObject(env, clazz);
    557     if (am == NULL) {
    558         return;
    559     }
    560 
    561     am->setLocale(locale8.c_str());
    562 }
    563 
    564 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
    565 {
    566     Vector<String8> locales;
    567 
    568     AssetManager* am = assetManagerForJavaObject(env, clazz);
    569     if (am == NULL) {
    570         return NULL;
    571     }
    572 
    573     am->getLocales(&locales);
    574 
    575     const int N = locales.size();
    576 
    577     jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
    578     if (result == NULL) {
    579         return NULL;
    580     }
    581 
    582     for (int i=0; i<N; i++) {
    583         jstring str = env->NewStringUTF(locales[i].string());
    584         if (str == NULL) {
    585             return NULL;
    586         }
    587         env->SetObjectArrayElement(result, i, str);
    588         env->DeleteLocalRef(str);
    589     }
    590 
    591     return result;
    592 }
    593 
    594 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
    595                                                           jint mcc, jint mnc,
    596                                                           jstring locale, jint orientation,
    597                                                           jint touchscreen, jint density,
    598                                                           jint keyboard, jint keyboardHidden,
    599                                                           jint navigation,
    600                                                           jint screenWidth, jint screenHeight,
    601                                                           jint smallestScreenWidthDp,
    602                                                           jint screenWidthDp, jint screenHeightDp,
    603                                                           jint screenLayout, jint uiMode,
    604                                                           jint sdkVersion)
    605 {
    606     AssetManager* am = assetManagerForJavaObject(env, clazz);
    607     if (am == NULL) {
    608         return;
    609     }
    610 
    611     ResTable_config config;
    612     memset(&config, 0, sizeof(config));
    613 
    614     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
    615 
    616     config.mcc = (uint16_t)mcc;
    617     config.mnc = (uint16_t)mnc;
    618     config.orientation = (uint8_t)orientation;
    619     config.touchscreen = (uint8_t)touchscreen;
    620     config.density = (uint16_t)density;
    621     config.keyboard = (uint8_t)keyboard;
    622     config.inputFlags = (uint8_t)keyboardHidden;
    623     config.navigation = (uint8_t)navigation;
    624     config.screenWidth = (uint16_t)screenWidth;
    625     config.screenHeight = (uint16_t)screenHeight;
    626     config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
    627     config.screenWidthDp = (uint16_t)screenWidthDp;
    628     config.screenHeightDp = (uint16_t)screenHeightDp;
    629     config.screenLayout = (uint8_t)screenLayout;
    630     config.uiMode = (uint8_t)uiMode;
    631     config.sdkVersion = (uint16_t)sdkVersion;
    632     config.minorVersion = 0;
    633     am->setConfiguration(config, locale8);
    634 
    635     if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
    636 }
    637 
    638 static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
    639                                                             jstring name,
    640                                                             jstring defType,
    641                                                             jstring defPackage)
    642 {
    643     ScopedStringChars name16(env, name);
    644     if (name16.get() == NULL) {
    645         return 0;
    646     }
    647 
    648     AssetManager* am = assetManagerForJavaObject(env, clazz);
    649     if (am == NULL) {
    650         return 0;
    651     }
    652 
    653     const char16_t* defType16 = defType
    654         ? env->GetStringChars(defType, NULL) : NULL;
    655     jsize defTypeLen = defType
    656         ? env->GetStringLength(defType) : 0;
    657     const char16_t* defPackage16 = defPackage
    658         ? env->GetStringChars(defPackage, NULL) : NULL;
    659     jsize defPackageLen = defPackage
    660         ? env->GetStringLength(defPackage) : 0;
    661 
    662     jint ident = am->getResources().identifierForName(
    663         name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
    664 
    665     if (defPackage16) {
    666         env->ReleaseStringChars(defPackage, defPackage16);
    667     }
    668     if (defType16) {
    669         env->ReleaseStringChars(defType, defType16);
    670     }
    671 
    672     return ident;
    673 }
    674 
    675 static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
    676                                                             jint resid)
    677 {
    678     AssetManager* am = assetManagerForJavaObject(env, clazz);
    679     if (am == NULL) {
    680         return NULL;
    681     }
    682 
    683     ResTable::resource_name name;
    684     if (!am->getResources().getResourceName(resid, true, &name)) {
    685         return NULL;
    686     }
    687 
    688     String16 str;
    689     if (name.package != NULL) {
    690         str.setTo(name.package, name.packageLen);
    691     }
    692     if (name.type8 != NULL || name.type != NULL) {
    693         if (str.size() > 0) {
    694             char16_t div = ':';
    695             str.append(&div, 1);
    696         }
    697         if (name.type8 != NULL) {
    698             str.append(String16(name.type8, name.typeLen));
    699         } else {
    700             str.append(name.type, name.typeLen);
    701         }
    702     }
    703     if (name.name8 != NULL || name.name != NULL) {
    704         if (str.size() > 0) {
    705             char16_t div = '/';
    706             str.append(&div, 1);
    707         }
    708         if (name.name8 != NULL) {
    709             str.append(String16(name.name8, name.nameLen));
    710         } else {
    711             str.append(name.name, name.nameLen);
    712         }
    713     }
    714 
    715     return env->NewString((const jchar*)str.string(), str.size());
    716 }
    717 
    718 static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
    719                                                                    jint resid)
    720 {
    721     AssetManager* am = assetManagerForJavaObject(env, clazz);
    722     if (am == NULL) {
    723         return NULL;
    724     }
    725 
    726     ResTable::resource_name name;
    727     if (!am->getResources().getResourceName(resid, true, &name)) {
    728         return NULL;
    729     }
    730 
    731     if (name.package != NULL) {
    732         return env->NewString((const jchar*)name.package, name.packageLen);
    733     }
    734 
    735     return NULL;
    736 }
    737 
    738 static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
    739                                                                 jint resid)
    740 {
    741     AssetManager* am = assetManagerForJavaObject(env, clazz);
    742     if (am == NULL) {
    743         return NULL;
    744     }
    745 
    746     ResTable::resource_name name;
    747     if (!am->getResources().getResourceName(resid, true, &name)) {
    748         return NULL;
    749     }
    750 
    751     if (name.type8 != NULL) {
    752         return env->NewStringUTF(name.type8);
    753     }
    754 
    755     if (name.type != NULL) {
    756         return env->NewString((const jchar*)name.type, name.typeLen);
    757     }
    758 
    759     return NULL;
    760 }
    761 
    762 static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
    763                                                                  jint resid)
    764 {
    765     AssetManager* am = assetManagerForJavaObject(env, clazz);
    766     if (am == NULL) {
    767         return NULL;
    768     }
    769 
    770     ResTable::resource_name name;
    771     if (!am->getResources().getResourceName(resid, true, &name)) {
    772         return NULL;
    773     }
    774 
    775     if (name.name8 != NULL) {
    776         return env->NewStringUTF(name.name8);
    777     }
    778 
    779     if (name.name != NULL) {
    780         return env->NewString((const jchar*)name.name, name.nameLen);
    781     }
    782 
    783     return NULL;
    784 }
    785 
    786 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
    787                                                            jint ident,
    788                                                            jshort density,
    789                                                            jobject outValue,
    790                                                            jboolean resolve)
    791 {
    792     if (outValue == NULL) {
    793          jniThrowNullPointerException(env, "outValue");
    794          return 0;
    795     }
    796     AssetManager* am = assetManagerForJavaObject(env, clazz);
    797     if (am == NULL) {
    798         return 0;
    799     }
    800     const ResTable& res(am->getResources());
    801 
    802     Res_value value;
    803     ResTable_config config;
    804     uint32_t typeSpecFlags;
    805     ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
    806 #if THROW_ON_BAD_ID
    807     if (block == BAD_INDEX) {
    808         jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
    809         return 0;
    810     }
    811 #endif
    812     uint32_t ref = ident;
    813     if (resolve) {
    814         block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
    815 #if THROW_ON_BAD_ID
    816         if (block == BAD_INDEX) {
    817             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
    818             return 0;
    819         }
    820 #endif
    821     }
    822     if (block >= 0) {
    823         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
    824     }
    825 
    826     return static_cast<jint>(block);
    827 }
    828 
    829 static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
    830                                                            jint ident, jint bagEntryId,
    831                                                            jobject outValue, jboolean resolve)
    832 {
    833     AssetManager* am = assetManagerForJavaObject(env, clazz);
    834     if (am == NULL) {
    835         return 0;
    836     }
    837     const ResTable& res(am->getResources());
    838 
    839     // Now lock down the resource object and start pulling stuff from it.
    840     res.lock();
    841 
    842     ssize_t block = -1;
    843     Res_value value;
    844 
    845     const ResTable::bag_entry* entry = NULL;
    846     uint32_t typeSpecFlags;
    847     ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
    848 
    849     for (ssize_t i=0; i<entryCount; i++) {
    850         if (((uint32_t)bagEntryId) == entry->map.name.ident) {
    851             block = entry->stringBlock;
    852             value = entry->map.value;
    853         }
    854         entry++;
    855     }
    856 
    857     res.unlock();
    858 
    859     if (block < 0) {
    860         return static_cast<jint>(block);
    861     }
    862 
    863     uint32_t ref = ident;
    864     if (resolve) {
    865         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
    866 #if THROW_ON_BAD_ID
    867         if (block == BAD_INDEX) {
    868             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
    869             return 0;
    870         }
    871 #endif
    872     }
    873     if (block >= 0) {
    874         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
    875     }
    876 
    877     return static_cast<jint>(block);
    878 }
    879 
    880 static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
    881 {
    882     AssetManager* am = assetManagerForJavaObject(env, clazz);
    883     if (am == NULL) {
    884         return 0;
    885     }
    886     return am->getResources().getTableCount();
    887 }
    888 
    889 static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
    890                                                            jint block)
    891 {
    892     AssetManager* am = assetManagerForJavaObject(env, clazz);
    893     if (am == NULL) {
    894         return 0;
    895     }
    896     return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
    897 }
    898 
    899 static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
    900                                                        jint cookie)
    901 {
    902     AssetManager* am = assetManagerForJavaObject(env, clazz);
    903     if (am == NULL) {
    904         return NULL;
    905     }
    906     String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
    907     if (name.length() == 0) {
    908         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
    909         return NULL;
    910     }
    911     jstring str = env->NewStringUTF(name.string());
    912     return str;
    913 }
    914 
    915 static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
    916 {
    917     AssetManager* am = assetManagerForJavaObject(env, clazz);
    918     if (am == NULL) {
    919         return 0;
    920     }
    921 
    922     const ResTable& res = am->getResources();
    923 
    924     jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
    925             gSparseArrayOffsets.constructor);
    926     const size_t N = res.getBasePackageCount();
    927     for (size_t i = 0; i < N; i++) {
    928         const String16 name = res.getBasePackageName(i);
    929         env->CallVoidMethod(sparseArray, gSparseArrayOffsets.put, (jint) res.getBasePackageId(i),
    930                 env->NewString(name, name.size()));
    931     }
    932     return sparseArray;
    933 }
    934 
    935 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
    936 {
    937     AssetManager* am = assetManagerForJavaObject(env, clazz);
    938     if (am == NULL) {
    939         return 0;
    940     }
    941     return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
    942 }
    943 
    944 static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
    945                                                      jlong themeHandle)
    946 {
    947     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
    948     delete theme;
    949 }
    950 
    951 static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
    952                                                          jlong themeHandle,
    953                                                          jint styleRes,
    954                                                          jboolean force)
    955 {
    956     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
    957     theme->applyStyle(styleRes, force ? true : false);
    958 }
    959 
    960 static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
    961                                                    jlong destHandle, jlong srcHandle)
    962 {
    963     ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
    964     ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
    965     dest->setTo(*src);
    966 }
    967 
    968 static jint android_content_AssetManager_loadThemeAttributeValue(
    969     JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
    970 {
    971     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
    972     const ResTable& res(theme->getResTable());
    973 
    974     Res_value value;
    975     // XXX value could be different in different configs!
    976     uint32_t typeSpecFlags = 0;
    977     ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
    978     uint32_t ref = 0;
    979     if (resolve) {
    980         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
    981 #if THROW_ON_BAD_ID
    982         if (block == BAD_INDEX) {
    983             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
    984             return 0;
    985         }
    986 #endif
    987     }
    988     return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
    989 }
    990 
    991 static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
    992                                                    jlong themeHandle, jint pri,
    993                                                    jstring tag, jstring prefix)
    994 {
    995     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
    996     const ResTable& res(theme->getResTable());
    997 
    998     // XXX Need to use params.
    999     theme->dumpToLog();
   1000 }
   1001 
   1002 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
   1003                                                           jlong themeToken,
   1004                                                           jint defStyleAttr,
   1005                                                           jint defStyleRes,
   1006                                                           jintArray inValues,
   1007                                                           jintArray attrs,
   1008                                                           jintArray outValues,
   1009                                                           jintArray outIndices)
   1010 {
   1011     if (themeToken == 0) {
   1012         jniThrowNullPointerException(env, "theme token");
   1013         return JNI_FALSE;
   1014     }
   1015     if (attrs == NULL) {
   1016         jniThrowNullPointerException(env, "attrs");
   1017         return JNI_FALSE;
   1018     }
   1019     if (outValues == NULL) {
   1020         jniThrowNullPointerException(env, "out values");
   1021         return JNI_FALSE;
   1022     }
   1023 
   1024     DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
   1025         themeToken, defStyleAttr, defStyleRes));
   1026 
   1027     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
   1028     const ResTable& res = theme->getResTable();
   1029     ResTable_config config;
   1030     Res_value value;
   1031 
   1032     const jsize NI = env->GetArrayLength(attrs);
   1033     const jsize NV = env->GetArrayLength(outValues);
   1034     if (NV < (NI*STYLE_NUM_ENTRIES)) {
   1035         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
   1036         return JNI_FALSE;
   1037     }
   1038 
   1039     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
   1040     if (src == NULL) {
   1041         return JNI_FALSE;
   1042     }
   1043 
   1044     jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
   1045     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
   1046 
   1047     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1048     jint* dest = baseDest;
   1049     if (dest == NULL) {
   1050         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1051         return JNI_FALSE;
   1052     }
   1053 
   1054     jint* indices = NULL;
   1055     int indicesIdx = 0;
   1056     if (outIndices != NULL) {
   1057         if (env->GetArrayLength(outIndices) > NI) {
   1058             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
   1059         }
   1060     }
   1061 
   1062     // Load default style from attribute, if specified...
   1063     uint32_t defStyleBagTypeSetFlags = 0;
   1064     if (defStyleAttr != 0) {
   1065         Res_value value;
   1066         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
   1067             if (value.dataType == Res_value::TYPE_REFERENCE) {
   1068                 defStyleRes = value.data;
   1069             }
   1070         }
   1071     }
   1072 
   1073     // Now lock down the resource object and start pulling stuff from it.
   1074     res.lock();
   1075 
   1076     // Retrieve the default style bag, if requested.
   1077     const ResTable::bag_entry* defStyleEnt = NULL;
   1078     uint32_t defStyleTypeSetFlags = 0;
   1079     ssize_t bagOff = defStyleRes != 0
   1080             ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
   1081     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
   1082     const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
   1083         (bagOff >= 0 ? bagOff : 0);;
   1084 
   1085     // Now iterate through all of the attributes that the client has requested,
   1086     // filling in each with whatever data we can find.
   1087     ssize_t block = 0;
   1088     uint32_t typeSetFlags;
   1089     for (jsize ii=0; ii<NI; ii++) {
   1090         const uint32_t curIdent = (uint32_t)src[ii];
   1091 
   1092         DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
   1093 
   1094         // Try to find a value for this attribute...  we prioritize values
   1095         // coming from, first XML attributes, then XML style, then default
   1096         // style, and finally the theme.
   1097         value.dataType = Res_value::TYPE_NULL;
   1098         value.data = 0;
   1099         typeSetFlags = 0;
   1100         config.density = 0;
   1101 
   1102         // Retrieve the current input value if available.
   1103         if (NSV > 0 && srcValues[ii] != 0) {
   1104             block = -1;
   1105             value.dataType = Res_value::TYPE_ATTRIBUTE;
   1106             value.data = srcValues[ii];
   1107             DEBUG_STYLES(ALOGI("-> From values: type=0x%x, data=0x%08x",
   1108                     value.dataType, value.data));
   1109         }
   1110 
   1111         // Skip through the default style values until the end or the next possible match.
   1112         while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
   1113             defStyleEnt++;
   1114         }
   1115         // Retrieve the current default style attribute if it matches, and step to next.
   1116         if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
   1117             if (value.dataType == Res_value::TYPE_NULL) {
   1118                 block = defStyleEnt->stringBlock;
   1119                 typeSetFlags = defStyleTypeSetFlags;
   1120                 value = defStyleEnt->map.value;
   1121                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
   1122                         value.dataType, value.data));
   1123             }
   1124             defStyleEnt++;
   1125         }
   1126 
   1127         uint32_t resid = 0;
   1128         if (value.dataType != Res_value::TYPE_NULL) {
   1129             // Take care of resolving the found resource to its final value.
   1130             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
   1131                     &resid, &typeSetFlags, &config);
   1132             if (newBlock >= 0) block = newBlock;
   1133             DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
   1134                     value.dataType, value.data));
   1135         } else {
   1136             // If we still don't have a value for this attribute, try to find
   1137             // it in the theme!
   1138             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
   1139             if (newBlock >= 0) {
   1140                 DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
   1141                         value.dataType, value.data));
   1142                 newBlock = res.resolveReference(&value, block, &resid,
   1143                         &typeSetFlags, &config);
   1144 #if THROW_ON_BAD_ID
   1145                 if (newBlock == BAD_INDEX) {
   1146                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1147                     return JNI_FALSE;
   1148                 }
   1149 #endif
   1150                 if (newBlock >= 0) block = newBlock;
   1151                 DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
   1152                         value.dataType, value.data));
   1153             }
   1154         }
   1155 
   1156         // Deal with the special @null value -- it turns back to TYPE_NULL.
   1157         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
   1158             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
   1159             value.dataType = Res_value::TYPE_NULL;
   1160             block = -1;
   1161         }
   1162 
   1163         DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
   1164                 curIdent, value.dataType, value.data));
   1165 
   1166         // Write the final value back to Java.
   1167         dest[STYLE_TYPE] = value.dataType;
   1168         dest[STYLE_DATA] = value.data;
   1169         dest[STYLE_ASSET_COOKIE] =
   1170             block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
   1171         dest[STYLE_RESOURCE_ID] = resid;
   1172         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
   1173         dest[STYLE_DENSITY] = config.density;
   1174 
   1175         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
   1176             indicesIdx++;
   1177             indices[indicesIdx] = ii;
   1178         }
   1179 
   1180         dest += STYLE_NUM_ENTRIES;
   1181     }
   1182 
   1183     res.unlock();
   1184 
   1185     if (indices != NULL) {
   1186         indices[0] = indicesIdx;
   1187         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
   1188     }
   1189     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1190     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
   1191     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1192 
   1193     return JNI_TRUE;
   1194 }
   1195 
   1196 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
   1197                                                         jlong themeToken,
   1198                                                         jint defStyleAttr,
   1199                                                         jint defStyleRes,
   1200                                                         jlong xmlParserToken,
   1201                                                         jintArray attrs,
   1202                                                         jintArray outValues,
   1203                                                         jintArray outIndices)
   1204 {
   1205     if (themeToken == 0) {
   1206         jniThrowNullPointerException(env, "theme token");
   1207         return JNI_FALSE;
   1208     }
   1209     if (attrs == NULL) {
   1210         jniThrowNullPointerException(env, "attrs");
   1211         return JNI_FALSE;
   1212     }
   1213     if (outValues == NULL) {
   1214         jniThrowNullPointerException(env, "out values");
   1215         return JNI_FALSE;
   1216     }
   1217 
   1218     DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
   1219         themeToken, defStyleAttr, defStyleRes, xmlParserToken));
   1220 
   1221     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
   1222     const ResTable& res = theme->getResTable();
   1223     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
   1224     ResTable_config config;
   1225     Res_value value;
   1226 
   1227     const jsize NI = env->GetArrayLength(attrs);
   1228     const jsize NV = env->GetArrayLength(outValues);
   1229     if (NV < (NI*STYLE_NUM_ENTRIES)) {
   1230         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
   1231         return JNI_FALSE;
   1232     }
   1233 
   1234     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
   1235     if (src == NULL) {
   1236         return JNI_FALSE;
   1237     }
   1238 
   1239     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1240     jint* dest = baseDest;
   1241     if (dest == NULL) {
   1242         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1243         return JNI_FALSE;
   1244     }
   1245 
   1246     jint* indices = NULL;
   1247     int indicesIdx = 0;
   1248     if (outIndices != NULL) {
   1249         if (env->GetArrayLength(outIndices) > NI) {
   1250             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
   1251         }
   1252     }
   1253 
   1254     // Load default style from attribute, if specified...
   1255     uint32_t defStyleBagTypeSetFlags = 0;
   1256     if (defStyleAttr != 0) {
   1257         Res_value value;
   1258         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
   1259             if (value.dataType == Res_value::TYPE_REFERENCE) {
   1260                 defStyleRes = value.data;
   1261             }
   1262         }
   1263     }
   1264 
   1265     // Retrieve the style class associated with the current XML tag.
   1266     int style = 0;
   1267     uint32_t styleBagTypeSetFlags = 0;
   1268     if (xmlParser != NULL) {
   1269         ssize_t idx = xmlParser->indexOfStyle();
   1270         if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
   1271             if (value.dataType == value.TYPE_ATTRIBUTE) {
   1272                 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
   1273                     value.dataType = Res_value::TYPE_NULL;
   1274                 }
   1275             }
   1276             if (value.dataType == value.TYPE_REFERENCE) {
   1277                 style = value.data;
   1278             }
   1279         }
   1280     }
   1281 
   1282     // Now lock down the resource object and start pulling stuff from it.
   1283     res.lock();
   1284 
   1285     // Retrieve the default style bag, if requested.
   1286     const ResTable::bag_entry* defStyleEnt = NULL;
   1287     uint32_t defStyleTypeSetFlags = 0;
   1288     ssize_t bagOff = defStyleRes != 0
   1289             ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
   1290     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
   1291     const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
   1292         (bagOff >= 0 ? bagOff : 0);
   1293 
   1294     // Retrieve the style class bag, if requested.
   1295     const ResTable::bag_entry* styleEnt = NULL;
   1296     uint32_t styleTypeSetFlags = 0;
   1297     bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
   1298     styleTypeSetFlags |= styleBagTypeSetFlags;
   1299     const ResTable::bag_entry* endStyleEnt = styleEnt +
   1300         (bagOff >= 0 ? bagOff : 0);
   1301 
   1302     // Retrieve the XML attributes, if requested.
   1303     const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
   1304     jsize ix=0;
   1305     uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
   1306 
   1307     static const ssize_t kXmlBlock = 0x10000000;
   1308 
   1309     // Now iterate through all of the attributes that the client has requested,
   1310     // filling in each with whatever data we can find.
   1311     ssize_t block = 0;
   1312     uint32_t typeSetFlags;
   1313     for (jsize ii=0; ii<NI; ii++) {
   1314         const uint32_t curIdent = (uint32_t)src[ii];
   1315 
   1316         DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
   1317 
   1318         // Try to find a value for this attribute...  we prioritize values
   1319         // coming from, first XML attributes, then XML style, then default
   1320         // style, and finally the theme.
   1321         value.dataType = Res_value::TYPE_NULL;
   1322         value.data = 0;
   1323         typeSetFlags = 0;
   1324         config.density = 0;
   1325 
   1326         // Skip through XML attributes until the end or the next possible match.
   1327         while (ix < NX && curIdent > curXmlAttr) {
   1328             ix++;
   1329             curXmlAttr = xmlParser->getAttributeNameResID(ix);
   1330         }
   1331         // Retrieve the current XML attribute if it matches, and step to next.
   1332         if (ix < NX && curIdent == curXmlAttr) {
   1333             block = kXmlBlock;
   1334             xmlParser->getAttributeValue(ix, &value);
   1335             ix++;
   1336             curXmlAttr = xmlParser->getAttributeNameResID(ix);
   1337             DEBUG_STYLES(ALOGI("-> From XML: type=0x%x, data=0x%08x",
   1338                     value.dataType, value.data));
   1339         }
   1340 
   1341         // Skip through the style values until the end or the next possible match.
   1342         while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
   1343             styleEnt++;
   1344         }
   1345         // Retrieve the current style attribute if it matches, and step to next.
   1346         if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
   1347             if (value.dataType == Res_value::TYPE_NULL) {
   1348                 block = styleEnt->stringBlock;
   1349                 typeSetFlags = styleTypeSetFlags;
   1350                 value = styleEnt->map.value;
   1351                 DEBUG_STYLES(ALOGI("-> From style: type=0x%x, data=0x%08x",
   1352                         value.dataType, value.data));
   1353             }
   1354             styleEnt++;
   1355         }
   1356 
   1357         // Skip through the default style values until the end or the next possible match.
   1358         while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
   1359             defStyleEnt++;
   1360         }
   1361         // Retrieve the current default style attribute if it matches, and step to next.
   1362         if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
   1363             if (value.dataType == Res_value::TYPE_NULL) {
   1364                 block = defStyleEnt->stringBlock;
   1365                 typeSetFlags = defStyleTypeSetFlags;
   1366                 value = defStyleEnt->map.value;
   1367                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
   1368                         value.dataType, value.data));
   1369             }
   1370             defStyleEnt++;
   1371         }
   1372 
   1373         uint32_t resid = 0;
   1374         if (value.dataType != Res_value::TYPE_NULL) {
   1375             // Take care of resolving the found resource to its final value.
   1376             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
   1377                     &resid, &typeSetFlags, &config);
   1378             if (newBlock >= 0) block = newBlock;
   1379             DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
   1380                     value.dataType, value.data));
   1381         } else {
   1382             // If we still don't have a value for this attribute, try to find
   1383             // it in the theme!
   1384             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
   1385             if (newBlock >= 0) {
   1386                 DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
   1387                         value.dataType, value.data));
   1388                 newBlock = res.resolveReference(&value, block, &resid,
   1389                         &typeSetFlags, &config);
   1390 #if THROW_ON_BAD_ID
   1391                 if (newBlock == BAD_INDEX) {
   1392                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1393                     return JNI_FALSE;
   1394                 }
   1395 #endif
   1396                 if (newBlock >= 0) block = newBlock;
   1397                 DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
   1398                         value.dataType, value.data));
   1399             }
   1400         }
   1401 
   1402         // Deal with the special @null value -- it turns back to TYPE_NULL.
   1403         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
   1404             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
   1405             value.dataType = Res_value::TYPE_NULL;
   1406             block = kXmlBlock;
   1407         }
   1408 
   1409         DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
   1410                 curIdent, value.dataType, value.data));
   1411 
   1412         // Write the final value back to Java.
   1413         dest[STYLE_TYPE] = value.dataType;
   1414         dest[STYLE_DATA] = value.data;
   1415         dest[STYLE_ASSET_COOKIE] =
   1416             block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
   1417         dest[STYLE_RESOURCE_ID] = resid;
   1418         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
   1419         dest[STYLE_DENSITY] = config.density;
   1420 
   1421         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
   1422             indicesIdx++;
   1423             indices[indicesIdx] = ii;
   1424         }
   1425 
   1426         dest += STYLE_NUM_ENTRIES;
   1427     }
   1428 
   1429     res.unlock();
   1430 
   1431     if (indices != NULL) {
   1432         indices[0] = indicesIdx;
   1433         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
   1434     }
   1435     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1436     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1437 
   1438     return JNI_TRUE;
   1439 }
   1440 
   1441 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
   1442                                                         jlong xmlParserToken,
   1443                                                         jintArray attrs,
   1444                                                         jintArray outValues,
   1445                                                         jintArray outIndices)
   1446 {
   1447     if (xmlParserToken == 0) {
   1448         jniThrowNullPointerException(env, "xmlParserToken");
   1449         return JNI_FALSE;
   1450     }
   1451     if (attrs == NULL) {
   1452         jniThrowNullPointerException(env, "attrs");
   1453         return JNI_FALSE;
   1454     }
   1455     if (outValues == NULL) {
   1456         jniThrowNullPointerException(env, "out values");
   1457         return JNI_FALSE;
   1458     }
   1459 
   1460     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1461     if (am == NULL) {
   1462         return JNI_FALSE;
   1463     }
   1464     const ResTable& res(am->getResources());
   1465     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
   1466     ResTable_config config;
   1467     Res_value value;
   1468 
   1469     const jsize NI = env->GetArrayLength(attrs);
   1470     const jsize NV = env->GetArrayLength(outValues);
   1471     if (NV < (NI*STYLE_NUM_ENTRIES)) {
   1472         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
   1473         return JNI_FALSE;
   1474     }
   1475 
   1476     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
   1477     if (src == NULL) {
   1478         return JNI_FALSE;
   1479     }
   1480 
   1481     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1482     jint* dest = baseDest;
   1483     if (dest == NULL) {
   1484         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1485         return JNI_FALSE;
   1486     }
   1487 
   1488     jint* indices = NULL;
   1489     int indicesIdx = 0;
   1490     if (outIndices != NULL) {
   1491         if (env->GetArrayLength(outIndices) > NI) {
   1492             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
   1493         }
   1494     }
   1495 
   1496     // Now lock down the resource object and start pulling stuff from it.
   1497     res.lock();
   1498 
   1499     // Retrieve the XML attributes, if requested.
   1500     const jsize NX = xmlParser->getAttributeCount();
   1501     jsize ix=0;
   1502     uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
   1503 
   1504     static const ssize_t kXmlBlock = 0x10000000;
   1505 
   1506     // Now iterate through all of the attributes that the client has requested,
   1507     // filling in each with whatever data we can find.
   1508     ssize_t block = 0;
   1509     uint32_t typeSetFlags;
   1510     for (jsize ii=0; ii<NI; ii++) {
   1511         const uint32_t curIdent = (uint32_t)src[ii];
   1512 
   1513         // Try to find a value for this attribute...
   1514         value.dataType = Res_value::TYPE_NULL;
   1515         value.data = 0;
   1516         typeSetFlags = 0;
   1517         config.density = 0;
   1518 
   1519         // Skip through XML attributes until the end or the next possible match.
   1520         while (ix < NX && curIdent > curXmlAttr) {
   1521             ix++;
   1522             curXmlAttr = xmlParser->getAttributeNameResID(ix);
   1523         }
   1524         // Retrieve the current XML attribute if it matches, and step to next.
   1525         if (ix < NX && curIdent == curXmlAttr) {
   1526             block = kXmlBlock;
   1527             xmlParser->getAttributeValue(ix, &value);
   1528             ix++;
   1529             curXmlAttr = xmlParser->getAttributeNameResID(ix);
   1530         }
   1531 
   1532         //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
   1533         uint32_t resid = 0;
   1534         if (value.dataType != Res_value::TYPE_NULL) {
   1535             // Take care of resolving the found resource to its final value.
   1536             //printf("Resolving attribute reference\n");
   1537             ssize_t newBlock = res.resolveReference(&value, block, &resid,
   1538                     &typeSetFlags, &config);
   1539 #if THROW_ON_BAD_ID
   1540             if (newBlock == BAD_INDEX) {
   1541                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1542                 return JNI_FALSE;
   1543             }
   1544 #endif
   1545             if (newBlock >= 0) block = newBlock;
   1546         }
   1547 
   1548         // Deal with the special @null value -- it turns back to TYPE_NULL.
   1549         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
   1550             value.dataType = Res_value::TYPE_NULL;
   1551         }
   1552 
   1553         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
   1554 
   1555         // Write the final value back to Java.
   1556         dest[STYLE_TYPE] = value.dataType;
   1557         dest[STYLE_DATA] = value.data;
   1558         dest[STYLE_ASSET_COOKIE] =
   1559             block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
   1560         dest[STYLE_RESOURCE_ID] = resid;
   1561         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
   1562         dest[STYLE_DENSITY] = config.density;
   1563 
   1564         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
   1565             indicesIdx++;
   1566             indices[indicesIdx] = ii;
   1567         }
   1568 
   1569         dest += STYLE_NUM_ENTRIES;
   1570     }
   1571 
   1572     res.unlock();
   1573 
   1574     if (indices != NULL) {
   1575         indices[0] = indicesIdx;
   1576         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
   1577     }
   1578 
   1579     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1580     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1581 
   1582     return JNI_TRUE;
   1583 }
   1584 
   1585 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
   1586                                                        jint id)
   1587 {
   1588     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1589     if (am == NULL) {
   1590         return 0;
   1591     }
   1592     const ResTable& res(am->getResources());
   1593 
   1594     res.lock();
   1595     const ResTable::bag_entry* defStyleEnt = NULL;
   1596     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
   1597     res.unlock();
   1598 
   1599     return static_cast<jint>(bagOff);
   1600 }
   1601 
   1602 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
   1603                                                         jint id,
   1604                                                         jintArray outValues)
   1605 {
   1606     if (outValues == NULL) {
   1607         jniThrowNullPointerException(env, "out values");
   1608         return JNI_FALSE;
   1609     }
   1610 
   1611     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1612     if (am == NULL) {
   1613         return JNI_FALSE;
   1614     }
   1615     const ResTable& res(am->getResources());
   1616     ResTable_config config;
   1617     Res_value value;
   1618     ssize_t block;
   1619 
   1620     const jsize NV = env->GetArrayLength(outValues);
   1621 
   1622     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1623     jint* dest = baseDest;
   1624     if (dest == NULL) {
   1625         jniThrowException(env, "java/lang/OutOfMemoryError", "");
   1626         return JNI_FALSE;
   1627     }
   1628 
   1629     // Now lock down the resource object and start pulling stuff from it.
   1630     res.lock();
   1631 
   1632     const ResTable::bag_entry* arrayEnt = NULL;
   1633     uint32_t arrayTypeSetFlags = 0;
   1634     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
   1635     const ResTable::bag_entry* endArrayEnt = arrayEnt +
   1636         (bagOff >= 0 ? bagOff : 0);
   1637 
   1638     int i = 0;
   1639     uint32_t typeSetFlags;
   1640     while (i < NV && arrayEnt < endArrayEnt) {
   1641         block = arrayEnt->stringBlock;
   1642         typeSetFlags = arrayTypeSetFlags;
   1643         config.density = 0;
   1644         value = arrayEnt->map.value;
   1645 
   1646         uint32_t resid = 0;
   1647         if (value.dataType != Res_value::TYPE_NULL) {
   1648             // Take care of resolving the found resource to its final value.
   1649             //printf("Resolving attribute reference\n");
   1650             ssize_t newBlock = res.resolveReference(&value, block, &resid,
   1651                     &typeSetFlags, &config);
   1652 #if THROW_ON_BAD_ID
   1653             if (newBlock == BAD_INDEX) {
   1654                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1655                 return JNI_FALSE;
   1656             }
   1657 #endif
   1658             if (newBlock >= 0) block = newBlock;
   1659         }
   1660 
   1661         // Deal with the special @null value -- it turns back to TYPE_NULL.
   1662         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
   1663             value.dataType = Res_value::TYPE_NULL;
   1664         }
   1665 
   1666         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
   1667 
   1668         // Write the final value back to Java.
   1669         dest[STYLE_TYPE] = value.dataType;
   1670         dest[STYLE_DATA] = value.data;
   1671         dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
   1672         dest[STYLE_RESOURCE_ID] = resid;
   1673         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
   1674         dest[STYLE_DENSITY] = config.density;
   1675         dest += STYLE_NUM_ENTRIES;
   1676         i+= STYLE_NUM_ENTRIES;
   1677         arrayEnt++;
   1678     }
   1679 
   1680     i /= STYLE_NUM_ENTRIES;
   1681 
   1682     res.unlock();
   1683 
   1684     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1685 
   1686     return i;
   1687 }
   1688 
   1689 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
   1690                                                          jint cookie,
   1691                                                          jstring fileName)
   1692 {
   1693     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1694     if (am == NULL) {
   1695         return 0;
   1696     }
   1697 
   1698     ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
   1699 
   1700     ScopedUtfChars fileName8(env, fileName);
   1701     if (fileName8.c_str() == NULL) {
   1702         return 0;
   1703     }
   1704 
   1705     int32_t assetCookie = static_cast<int32_t>(cookie);
   1706     Asset* a = assetCookie
   1707         ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
   1708         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
   1709 
   1710     if (a == NULL) {
   1711         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
   1712         return 0;
   1713     }
   1714 
   1715     const DynamicRefTable* dynamicRefTable =
   1716             am->getResources().getDynamicRefTableForCookie(assetCookie);
   1717     ResXMLTree* block = new ResXMLTree(dynamicRefTable);
   1718     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
   1719     a->close();
   1720     delete a;
   1721 
   1722     if (err != NO_ERROR) {
   1723         jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
   1724         return 0;
   1725     }
   1726 
   1727     return reinterpret_cast<jlong>(block);
   1728 }
   1729 
   1730 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
   1731                                                                  jint arrayResId)
   1732 {
   1733     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1734     if (am == NULL) {
   1735         return NULL;
   1736     }
   1737     const ResTable& res(am->getResources());
   1738 
   1739     const ResTable::bag_entry* startOfBag;
   1740     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1741     if (N < 0) {
   1742         return NULL;
   1743     }
   1744 
   1745     jintArray array = env->NewIntArray(N * 2);
   1746     if (array == NULL) {
   1747         res.unlockBag(startOfBag);
   1748         return NULL;
   1749     }
   1750 
   1751     Res_value value;
   1752     const ResTable::bag_entry* bag = startOfBag;
   1753     for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
   1754         jint stringIndex = -1;
   1755         jint stringBlock = 0;
   1756         value = bag->map.value;
   1757 
   1758         // Take care of resolving the found resource to its final value.
   1759         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
   1760         if (value.dataType == Res_value::TYPE_STRING) {
   1761             stringIndex = value.data;
   1762         }
   1763 
   1764 #if THROW_ON_BAD_ID
   1765         if (stringBlock == BAD_INDEX) {
   1766             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1767             return array;
   1768         }
   1769 #endif
   1770 
   1771         //todo: It might be faster to allocate a C array to contain
   1772         //      the blocknums and indices, put them in there and then
   1773         //      do just one SetIntArrayRegion()
   1774         env->SetIntArrayRegion(array, j, 1, &stringBlock);
   1775         env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
   1776         j = j + 2;
   1777     }
   1778     res.unlockBag(startOfBag);
   1779     return array;
   1780 }
   1781 
   1782 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
   1783                                                                         jint arrayResId)
   1784 {
   1785     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1786     if (am == NULL) {
   1787         return NULL;
   1788     }
   1789     const ResTable& res(am->getResources());
   1790 
   1791     const ResTable::bag_entry* startOfBag;
   1792     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1793     if (N < 0) {
   1794         return NULL;
   1795     }
   1796 
   1797     jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
   1798     if (env->ExceptionCheck()) {
   1799         res.unlockBag(startOfBag);
   1800         return NULL;
   1801     }
   1802 
   1803     Res_value value;
   1804     const ResTable::bag_entry* bag = startOfBag;
   1805     size_t strLen = 0;
   1806     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1807         value = bag->map.value;
   1808         jstring str = NULL;
   1809 
   1810         // Take care of resolving the found resource to its final value.
   1811         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
   1812 #if THROW_ON_BAD_ID
   1813         if (block == BAD_INDEX) {
   1814             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1815             return array;
   1816         }
   1817 #endif
   1818         if (value.dataType == Res_value::TYPE_STRING) {
   1819             const ResStringPool* pool = res.getTableStringBlock(block);
   1820             const char* str8 = pool->string8At(value.data, &strLen);
   1821             if (str8 != NULL) {
   1822                 str = env->NewStringUTF(str8);
   1823             } else {
   1824                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
   1825                 str = env->NewString(str16, strLen);
   1826             }
   1827 
   1828             // If one of our NewString{UTF} calls failed due to memory, an
   1829             // exception will be pending.
   1830             if (env->ExceptionCheck()) {
   1831                 res.unlockBag(startOfBag);
   1832                 return NULL;
   1833             }
   1834 
   1835             env->SetObjectArrayElement(array, i, str);
   1836 
   1837             // str is not NULL at that point, otherwise ExceptionCheck would have been true.
   1838             // If we have a large amount of strings in our array, we might
   1839             // overflow the local reference table of the VM.
   1840             env->DeleteLocalRef(str);
   1841         }
   1842     }
   1843     res.unlockBag(startOfBag);
   1844     return array;
   1845 }
   1846 
   1847 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
   1848                                                                         jint arrayResId)
   1849 {
   1850     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1851     if (am == NULL) {
   1852         return NULL;
   1853     }
   1854     const ResTable& res(am->getResources());
   1855 
   1856     const ResTable::bag_entry* startOfBag;
   1857     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1858     if (N < 0) {
   1859         return NULL;
   1860     }
   1861 
   1862     jintArray array = env->NewIntArray(N);
   1863     if (array == NULL) {
   1864         res.unlockBag(startOfBag);
   1865         return NULL;
   1866     }
   1867 
   1868     Res_value value;
   1869     const ResTable::bag_entry* bag = startOfBag;
   1870     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1871         value = bag->map.value;
   1872 
   1873         // Take care of resolving the found resource to its final value.
   1874         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
   1875 #if THROW_ON_BAD_ID
   1876         if (block == BAD_INDEX) {
   1877             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1878             return array;
   1879         }
   1880 #endif
   1881         if (value.dataType >= Res_value::TYPE_FIRST_INT
   1882                 && value.dataType <= Res_value::TYPE_LAST_INT) {
   1883             int intVal = value.data;
   1884             env->SetIntArrayRegion(array, i, 1, &intVal);
   1885         }
   1886     }
   1887     res.unlockBag(startOfBag);
   1888     return array;
   1889 }
   1890 
   1891 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
   1892                                                                  jint styleId)
   1893 {
   1894     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1895     if (am == NULL) {
   1896         return NULL;
   1897     }
   1898     const ResTable& res(am->getResources());
   1899 
   1900     const ResTable::bag_entry* startOfBag;
   1901     const ssize_t N = res.lockBag(styleId, &startOfBag);
   1902     if (N < 0) {
   1903         return NULL;
   1904     }
   1905 
   1906     jintArray array = env->NewIntArray(N);
   1907     if (array == NULL) {
   1908         res.unlockBag(startOfBag);
   1909         return NULL;
   1910     }
   1911 
   1912     Res_value value;
   1913     const ResTable::bag_entry* bag = startOfBag;
   1914     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1915         int resourceId = bag->map.name.ident;
   1916         env->SetIntArrayRegion(array, i, 1, &resourceId);
   1917     }
   1918     res.unlockBag(startOfBag);
   1919     return array;
   1920 }
   1921 
   1922 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
   1923 {
   1924     if (isSystem) {
   1925         verifySystemIdmaps();
   1926     }
   1927     AssetManager* am = new AssetManager();
   1928     if (am == NULL) {
   1929         jniThrowException(env, "java/lang/OutOfMemoryError", "");
   1930         return;
   1931     }
   1932 
   1933     am->addDefaultAssets();
   1934 
   1935     ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
   1936     env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
   1937 }
   1938 
   1939 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
   1940 {
   1941     AssetManager* am = (AssetManager*)
   1942         (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
   1943     ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
   1944     if (am != NULL) {
   1945         delete am;
   1946         env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
   1947     }
   1948 }
   1949 
   1950 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
   1951 {
   1952     return Asset::getGlobalCount();
   1953 }
   1954 
   1955 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
   1956 {
   1957     String8 alloc = Asset::getAssetAllocations();
   1958     if (alloc.length() <= 0) {
   1959         return NULL;
   1960     }
   1961 
   1962     jstring str = env->NewStringUTF(alloc.string());
   1963     return str;
   1964 }
   1965 
   1966 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
   1967 {
   1968     return AssetManager::getGlobalCount();
   1969 }
   1970 
   1971 // ----------------------------------------------------------------------------
   1972 
   1973 /*
   1974  * JNI registration.
   1975  */
   1976 static JNINativeMethod gAssetManagerMethods[] = {
   1977     /* name, signature, funcPtr */
   1978 
   1979     // Basic asset stuff.
   1980     { "openAsset",      "(Ljava/lang/String;I)J",
   1981         (void*) android_content_AssetManager_openAsset },
   1982     { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1983         (void*) android_content_AssetManager_openAssetFd },
   1984     { "openNonAssetNative", "(ILjava/lang/String;I)J",
   1985         (void*) android_content_AssetManager_openNonAssetNative },
   1986     { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1987         (void*) android_content_AssetManager_openNonAssetFdNative },
   1988     { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
   1989         (void*) android_content_AssetManager_list },
   1990     { "destroyAsset",   "(J)V",
   1991         (void*) android_content_AssetManager_destroyAsset },
   1992     { "readAssetChar",  "(J)I",
   1993         (void*) android_content_AssetManager_readAssetChar },
   1994     { "readAsset",      "(J[BII)I",
   1995         (void*) android_content_AssetManager_readAsset },
   1996     { "seekAsset",      "(JJI)J",
   1997         (void*) android_content_AssetManager_seekAsset },
   1998     { "getAssetLength", "(J)J",
   1999         (void*) android_content_AssetManager_getAssetLength },
   2000     { "getAssetRemainingLength", "(J)J",
   2001         (void*) android_content_AssetManager_getAssetRemainingLength },
   2002     { "addAssetPathNative", "(Ljava/lang/String;)I",
   2003         (void*) android_content_AssetManager_addAssetPath },
   2004     { "addOverlayPath",   "(Ljava/lang/String;)I",
   2005         (void*) android_content_AssetManager_addOverlayPath },
   2006     { "isUpToDate",     "()Z",
   2007         (void*) android_content_AssetManager_isUpToDate },
   2008 
   2009     // Resources.
   2010     { "setLocale",      "(Ljava/lang/String;)V",
   2011         (void*) android_content_AssetManager_setLocale },
   2012     { "getLocales",      "()[Ljava/lang/String;",
   2013         (void*) android_content_AssetManager_getLocales },
   2014     { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
   2015         (void*) android_content_AssetManager_setConfiguration },
   2016     { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
   2017         (void*) android_content_AssetManager_getResourceIdentifier },
   2018     { "getResourceName","(I)Ljava/lang/String;",
   2019         (void*) android_content_AssetManager_getResourceName },
   2020     { "getResourcePackageName","(I)Ljava/lang/String;",
   2021         (void*) android_content_AssetManager_getResourcePackageName },
   2022     { "getResourceTypeName","(I)Ljava/lang/String;",
   2023         (void*) android_content_AssetManager_getResourceTypeName },
   2024     { "getResourceEntryName","(I)Ljava/lang/String;",
   2025         (void*) android_content_AssetManager_getResourceEntryName },
   2026     { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
   2027         (void*) android_content_AssetManager_loadResourceValue },
   2028     { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
   2029         (void*) android_content_AssetManager_loadResourceBagValue },
   2030     { "getStringBlockCount","()I",
   2031         (void*) android_content_AssetManager_getStringBlockCount },
   2032     { "getNativeStringBlock","(I)J",
   2033         (void*) android_content_AssetManager_getNativeStringBlock },
   2034     { "getCookieName","(I)Ljava/lang/String;",
   2035         (void*) android_content_AssetManager_getCookieName },
   2036     { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
   2037         (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
   2038 
   2039     // Themes.
   2040     { "newTheme", "()J",
   2041         (void*) android_content_AssetManager_newTheme },
   2042     { "deleteTheme", "(J)V",
   2043         (void*) android_content_AssetManager_deleteTheme },
   2044     { "applyThemeStyle", "(JIZ)V",
   2045         (void*) android_content_AssetManager_applyThemeStyle },
   2046     { "copyTheme", "(JJ)V",
   2047         (void*) android_content_AssetManager_copyTheme },
   2048     { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
   2049         (void*) android_content_AssetManager_loadThemeAttributeValue },
   2050     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
   2051         (void*) android_content_AssetManager_dumpTheme },
   2052     { "applyStyle","(JIIJ[I[I[I)Z",
   2053         (void*) android_content_AssetManager_applyStyle },
   2054     { "resolveAttrs","(JII[I[I[I[I)Z",
   2055         (void*) android_content_AssetManager_resolveAttrs },
   2056     { "retrieveAttributes","(J[I[I[I)Z",
   2057         (void*) android_content_AssetManager_retrieveAttributes },
   2058     { "getArraySize","(I)I",
   2059         (void*) android_content_AssetManager_getArraySize },
   2060     { "retrieveArray","(I[I)I",
   2061         (void*) android_content_AssetManager_retrieveArray },
   2062 
   2063     // XML files.
   2064     { "openXmlAssetNative", "(ILjava/lang/String;)J",
   2065         (void*) android_content_AssetManager_openXmlAssetNative },
   2066 
   2067     // Arrays.
   2068     { "getArrayStringResource","(I)[Ljava/lang/String;",
   2069         (void*) android_content_AssetManager_getArrayStringResource },
   2070     { "getArrayStringInfo","(I)[I",
   2071         (void*) android_content_AssetManager_getArrayStringInfo },
   2072     { "getArrayIntResource","(I)[I",
   2073         (void*) android_content_AssetManager_getArrayIntResource },
   2074     { "getStyleAttributes","(I)[I",
   2075         (void*) android_content_AssetManager_getStyleAttributes },
   2076 
   2077     // Bookkeeping.
   2078     { "init",           "(Z)V",
   2079         (void*) android_content_AssetManager_init },
   2080     { "destroy",        "()V",
   2081         (void*) android_content_AssetManager_destroy },
   2082     { "getGlobalAssetCount", "()I",
   2083         (void*) android_content_AssetManager_getGlobalAssetCount },
   2084     { "getAssetAllocations", "()Ljava/lang/String;",
   2085         (void*) android_content_AssetManager_getAssetAllocations },
   2086     { "getGlobalAssetManagerCount", "()I",
   2087         (void*) android_content_AssetManager_getGlobalAssetCount },
   2088 };
   2089 
   2090 int register_android_content_AssetManager(JNIEnv* env)
   2091 {
   2092     jclass typedValue = env->FindClass("android/util/TypedValue");
   2093     LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
   2094     gTypedValueOffsets.mType
   2095         = env->GetFieldID(typedValue, "type", "I");
   2096     LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
   2097     gTypedValueOffsets.mData
   2098         = env->GetFieldID(typedValue, "data", "I");
   2099     LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
   2100     gTypedValueOffsets.mString
   2101         = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
   2102     LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
   2103     gTypedValueOffsets.mAssetCookie
   2104         = env->GetFieldID(typedValue, "assetCookie", "I");
   2105     LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
   2106     gTypedValueOffsets.mResourceId
   2107         = env->GetFieldID(typedValue, "resourceId", "I");
   2108     LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
   2109     gTypedValueOffsets.mChangingConfigurations
   2110         = env->GetFieldID(typedValue, "changingConfigurations", "I");
   2111     LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
   2112     gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
   2113     LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
   2114 
   2115     jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
   2116     LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
   2117     gAssetFileDescriptorOffsets.mFd
   2118         = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
   2119     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
   2120     gAssetFileDescriptorOffsets.mStartOffset
   2121         = env->GetFieldID(assetFd, "mStartOffset", "J");
   2122     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
   2123     gAssetFileDescriptorOffsets.mLength
   2124         = env->GetFieldID(assetFd, "mLength", "J");
   2125     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
   2126 
   2127     jclass assetManager = env->FindClass("android/content/res/AssetManager");
   2128     LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
   2129     gAssetManagerOffsets.mObject
   2130         = env->GetFieldID(assetManager, "mObject", "J");
   2131     LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
   2132 
   2133     jclass stringClass = env->FindClass("java/lang/String");
   2134     LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
   2135     g_stringClass = (jclass)env->NewGlobalRef(stringClass);
   2136     LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
   2137 
   2138     jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
   2139     LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
   2140     gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
   2141     gSparseArrayOffsets.constructor =
   2142             env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
   2143     LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
   2144     gSparseArrayOffsets.put =
   2145             env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
   2146     LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
   2147 
   2148     return AndroidRuntime::registerNativeMethods(env,
   2149             "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
   2150 }
   2151 
   2152 }; // namespace android
   2153