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