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