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