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 #include <sys/system_properties.h>
     29 
     30 #include <private/android_filesystem_config.h> // for AID_SYSTEM
     31 
     32 #include "androidfw/Asset.h"
     33 #include "androidfw/AssetManager.h"
     34 #include "androidfw/AttributeResolution.h"
     35 #include "androidfw/ResourceTypes.h"
     36 #include "android_runtime/AndroidRuntime.h"
     37 #include "android_util_Binder.h"
     38 #include "core_jni_helpers.h"
     39 #include "jni.h"
     40 #include "JNIHelp.h"
     41 #include "ScopedStringChars.h"
     42 #include "ScopedUtfChars.h"
     43 #include "utils/Log.h"
     44 #include "utils/misc.h"
     45 #include "utils/String8.h"
     46 
     47 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
     48 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
     49 
     50 
     51 namespace android {
     52 
     53 static const bool kThrowOnBadId = false;
     54 
     55 // ----------------------------------------------------------------------------
     56 
     57 static struct typedvalue_offsets_t
     58 {
     59     jfieldID mType;
     60     jfieldID mData;
     61     jfieldID mString;
     62     jfieldID mAssetCookie;
     63     jfieldID mResourceId;
     64     jfieldID mChangingConfigurations;
     65     jfieldID mDensity;
     66 } gTypedValueOffsets;
     67 
     68 static struct assetfiledescriptor_offsets_t
     69 {
     70     jfieldID mFd;
     71     jfieldID mStartOffset;
     72     jfieldID mLength;
     73 } gAssetFileDescriptorOffsets;
     74 
     75 static struct assetmanager_offsets_t
     76 {
     77     jfieldID mObject;
     78 } gAssetManagerOffsets;
     79 
     80 static struct sparsearray_offsets_t
     81 {
     82     jclass classObject;
     83     jmethodID constructor;
     84     jmethodID put;
     85 } gSparseArrayOffsets;
     86 
     87 static struct configuration_offsets_t
     88 {
     89     jclass classObject;
     90     jmethodID constructor;
     91     jfieldID mSmallestScreenWidthDpOffset;
     92     jfieldID mScreenWidthDpOffset;
     93     jfieldID mScreenHeightDpOffset;
     94 } gConfigurationOffsets;
     95 
     96 jclass g_stringClass = NULL;
     97 
     98 // ----------------------------------------------------------------------------
     99 
    100 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
    101                       const Res_value& value, uint32_t ref, ssize_t block,
    102                       uint32_t typeSpecFlags, ResTable_config* config = NULL);
    103 
    104 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
    105                const Res_value& value, uint32_t ref, ssize_t block,
    106                uint32_t typeSpecFlags, ResTable_config* config)
    107 {
    108     env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
    109     env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
    110                      static_cast<jint>(table->getTableCookie(block)));
    111     env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
    112     env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
    113     env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
    114     env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
    115             typeSpecFlags);
    116     if (config != NULL) {
    117         env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
    118     }
    119     return block;
    120 }
    121 
    122 // This is called by zygote (running as user root) as part of preloadResources.
    123 static void verifySystemIdmaps()
    124 {
    125     pid_t pid;
    126     char system_id[10];
    127 
    128     snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
    129 
    130     switch (pid = fork()) {
    131         case -1:
    132             ALOGE("failed to fork for idmap: %s", strerror(errno));
    133             break;
    134         case 0: // child
    135             {
    136                 struct __user_cap_header_struct capheader;
    137                 struct __user_cap_data_struct capdata;
    138 
    139                 memset(&capheader, 0, sizeof(capheader));
    140                 memset(&capdata, 0, sizeof(capdata));
    141 
    142                 capheader.version = _LINUX_CAPABILITY_VERSION;
    143                 capheader.pid = 0;
    144 
    145                 if (capget(&capheader, &capdata) != 0) {
    146                     ALOGE("capget: %s\n", strerror(errno));
    147                     exit(1);
    148                 }
    149 
    150                 capdata.effective = capdata.permitted;
    151                 if (capset(&capheader, &capdata) != 0) {
    152                     ALOGE("capset: %s\n", strerror(errno));
    153                     exit(1);
    154                 }
    155 
    156                 if (setgid(AID_SYSTEM) != 0) {
    157                     ALOGE("setgid: %s\n", strerror(errno));
    158                     exit(1);
    159                 }
    160 
    161                 if (setuid(AID_SYSTEM) != 0) {
    162                     ALOGE("setuid: %s\n", strerror(errno));
    163                     exit(1);
    164                 }
    165 
    166                 // Generic idmap parameters
    167                 const char* argv[8];
    168                 int argc = 0;
    169                 struct stat st;
    170 
    171                 memset(argv, NULL, sizeof(argv));
    172                 argv[argc++] = AssetManager::IDMAP_BIN;
    173                 argv[argc++] = "--scan";
    174                 argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
    175                 argv[argc++] = AssetManager::TARGET_APK_PATH;
    176                 argv[argc++] = AssetManager::IDMAP_DIR;
    177 
    178                 // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
    179                 // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
    180                 char subdir[PROP_VALUE_MAX];
    181                 int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
    182                 if (len > 0) {
    183                     String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
    184                     if (stat(overlayPath.string(), &st) == 0) {
    185                         argv[argc++] = overlayPath.string();
    186                     }
    187                 }
    188                 if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
    189                     argv[argc++] = AssetManager::OVERLAY_DIR;
    190                 }
    191 
    192                 // Finally, invoke idmap (if any overlay directory exists)
    193                 if (argc > 5) {
    194                     execv(AssetManager::IDMAP_BIN, (char* const*)argv);
    195                     ALOGE("failed to execv for idmap: %s", strerror(errno));
    196                     exit(1); // should never get here
    197                 } else {
    198                     exit(0);
    199                 }
    200             }
    201             break;
    202         default: // parent
    203             waitpid(pid, NULL, 0);
    204             break;
    205     }
    206 }
    207 
    208 // ----------------------------------------------------------------------------
    209 
    210 // this guy is exported to other jni routines
    211 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
    212 {
    213     jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
    214     AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
    215     if (am != NULL) {
    216         return am;
    217     }
    218     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
    219     return NULL;
    220 }
    221 
    222 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
    223                                                 jstring fileName, jint mode)
    224 {
    225     AssetManager* am = assetManagerForJavaObject(env, clazz);
    226     if (am == NULL) {
    227         return 0;
    228     }
    229 
    230     ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
    231 
    232     ScopedUtfChars fileName8(env, fileName);
    233     if (fileName8.c_str() == NULL) {
    234         jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
    235         return -1;
    236     }
    237 
    238     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
    239         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
    240         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    241         return -1;
    242     }
    243 
    244     Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
    245 
    246     if (a == NULL) {
    247         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    248         return -1;
    249     }
    250 
    251     //printf("Created Asset Stream: %p\n", a);
    252 
    253     return reinterpret_cast<jlong>(a);
    254 }
    255 
    256 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
    257 {
    258     off64_t startOffset, length;
    259     int fd = a->openFileDescriptor(&startOffset, &length);
    260     delete a;
    261 
    262     if (fd < 0) {
    263         jniThrowException(env, "java/io/FileNotFoundException",
    264                 "This file can not be opened as a file descriptor; it is probably compressed");
    265         return NULL;
    266     }
    267 
    268     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
    269     if (offsets == NULL) {
    270         close(fd);
    271         return NULL;
    272     }
    273 
    274     offsets[0] = startOffset;
    275     offsets[1] = length;
    276 
    277     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
    278 
    279     jobject fileDesc = jniCreateFileDescriptor(env, fd);
    280     if (fileDesc == NULL) {
    281         close(fd);
    282         return NULL;
    283     }
    284 
    285     return newParcelFileDescriptor(env, fileDesc);
    286 }
    287 
    288 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
    289                                                 jstring fileName, jlongArray outOffsets)
    290 {
    291     AssetManager* am = assetManagerForJavaObject(env, clazz);
    292     if (am == NULL) {
    293         return NULL;
    294     }
    295 
    296     ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
    297 
    298     ScopedUtfChars fileName8(env, fileName);
    299     if (fileName8.c_str() == NULL) {
    300         return NULL;
    301     }
    302 
    303     Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
    304 
    305     if (a == NULL) {
    306         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    307         return NULL;
    308     }
    309 
    310     //printf("Created Asset Stream: %p\n", a);
    311 
    312     return returnParcelFileDescriptor(env, a, outOffsets);
    313 }
    314 
    315 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
    316                                                          jint cookie,
    317                                                          jstring fileName,
    318                                                          jint mode)
    319 {
    320     AssetManager* am = assetManagerForJavaObject(env, clazz);
    321     if (am == NULL) {
    322         return 0;
    323     }
    324 
    325     ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
    326 
    327     ScopedUtfChars fileName8(env, fileName);
    328     if (fileName8.c_str() == NULL) {
    329         return -1;
    330     }
    331 
    332     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
    333         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
    334         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
    335         return -1;
    336     }
    337 
    338     Asset* a = cookie
    339         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
    340                 (Asset::AccessMode)mode)
    341         : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
    342 
    343     if (a == NULL) {
    344         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    345         return -1;
    346     }
    347 
    348     //printf("Created Asset Stream: %p\n", a);
    349 
    350     return reinterpret_cast<jlong>(a);
    351 }
    352 
    353 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
    354                                                          jint cookie,
    355                                                          jstring fileName,
    356                                                          jlongArray outOffsets)
    357 {
    358     AssetManager* am = assetManagerForJavaObject(env, clazz);
    359     if (am == NULL) {
    360         return NULL;
    361     }
    362 
    363     ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
    364 
    365     ScopedUtfChars fileName8(env, fileName);
    366     if (fileName8.c_str() == NULL) {
    367         return NULL;
    368     }
    369 
    370     Asset* a = cookie
    371         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
    372         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
    373 
    374     if (a == NULL) {
    375         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    376         return NULL;
    377     }
    378 
    379     //printf("Created Asset Stream: %p\n", a);
    380 
    381     return returnParcelFileDescriptor(env, a, outOffsets);
    382 }
    383 
    384 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
    385                                                    jstring fileName)
    386 {
    387     AssetManager* am = assetManagerForJavaObject(env, clazz);
    388     if (am == NULL) {
    389         return NULL;
    390     }
    391 
    392     ScopedUtfChars fileName8(env, fileName);
    393     if (fileName8.c_str() == NULL) {
    394         return NULL;
    395     }
    396 
    397     AssetDir* dir = am->openDir(fileName8.c_str());
    398 
    399     if (dir == NULL) {
    400         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
    401         return NULL;
    402     }
    403 
    404     size_t N = dir->getFileCount();
    405 
    406     jobjectArray array = env->NewObjectArray(dir->getFileCount(),
    407                                                 g_stringClass, NULL);
    408     if (array == NULL) {
    409         delete dir;
    410         return NULL;
    411     }
    412 
    413     for (size_t i=0; i<N; i++) {
    414         const String8& name = dir->getFileName(i);
    415         jstring str = env->NewStringUTF(name.string());
    416         if (str == NULL) {
    417             delete dir;
    418             return NULL;
    419         }
    420         env->SetObjectArrayElement(array, i, str);
    421         env->DeleteLocalRef(str);
    422     }
    423 
    424     delete dir;
    425 
    426     return array;
    427 }
    428 
    429 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
    430                                                       jlong assetHandle)
    431 {
    432     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    433 
    434     //printf("Destroying Asset Stream: %p\n", a);
    435 
    436     if (a == NULL) {
    437         jniThrowNullPointerException(env, "asset");
    438         return;
    439     }
    440 
    441     delete a;
    442 }
    443 
    444 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
    445                                                        jlong assetHandle)
    446 {
    447     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    448 
    449     if (a == NULL) {
    450         jniThrowNullPointerException(env, "asset");
    451         return -1;
    452     }
    453 
    454     uint8_t b;
    455     ssize_t res = a->read(&b, 1);
    456     return res == 1 ? b : -1;
    457 }
    458 
    459 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
    460                                                 jlong assetHandle, jbyteArray bArray,
    461                                                 jint off, jint len)
    462 {
    463     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    464 
    465     if (a == NULL || bArray == NULL) {
    466         jniThrowNullPointerException(env, "asset");
    467         return -1;
    468     }
    469 
    470     if (len == 0) {
    471         return 0;
    472     }
    473 
    474     jsize bLen = env->GetArrayLength(bArray);
    475     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
    476         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
    477         return -1;
    478     }
    479 
    480     jbyte* b = env->GetByteArrayElements(bArray, NULL);
    481     ssize_t res = a->read(b+off, len);
    482     env->ReleaseByteArrayElements(bArray, b, 0);
    483 
    484     if (res > 0) return static_cast<jint>(res);
    485 
    486     if (res < 0) {
    487         jniThrowException(env, "java/io/IOException", "");
    488     }
    489     return -1;
    490 }
    491 
    492 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
    493                                                  jlong assetHandle,
    494                                                  jlong offset, jint whence)
    495 {
    496     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    497 
    498     if (a == NULL) {
    499         jniThrowNullPointerException(env, "asset");
    500         return -1;
    501     }
    502 
    503     return a->seek(
    504         offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
    505 }
    506 
    507 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
    508                                                       jlong assetHandle)
    509 {
    510     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    511 
    512     if (a == NULL) {
    513         jniThrowNullPointerException(env, "asset");
    514         return -1;
    515     }
    516 
    517     return a->getLength();
    518 }
    519 
    520 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
    521                                                                jlong assetHandle)
    522 {
    523     Asset* a = reinterpret_cast<Asset*>(assetHandle);
    524 
    525     if (a == NULL) {
    526         jniThrowNullPointerException(env, "asset");
    527         return -1;
    528     }
    529 
    530     return a->getRemainingLength();
    531 }
    532 
    533 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
    534                                                        jstring path, jboolean appAsLib)
    535 {
    536     ScopedUtfChars path8(env, path);
    537     if (path8.c_str() == NULL) {
    538         return 0;
    539     }
    540 
    541     AssetManager* am = assetManagerForJavaObject(env, clazz);
    542     if (am == NULL) {
    543         return 0;
    544     }
    545 
    546     int32_t cookie;
    547     bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
    548 
    549     return (res) ? static_cast<jint>(cookie) : 0;
    550 }
    551 
    552 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
    553                                                      jstring idmapPath)
    554 {
    555     ScopedUtfChars idmapPath8(env, idmapPath);
    556     if (idmapPath8.c_str() == NULL) {
    557         return 0;
    558     }
    559 
    560     AssetManager* am = assetManagerForJavaObject(env, clazz);
    561     if (am == NULL) {
    562         return 0;
    563     }
    564 
    565     int32_t cookie;
    566     bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
    567 
    568     return (res) ? (jint)cookie : 0;
    569 }
    570 
    571 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
    572 {
    573     AssetManager* am = assetManagerForJavaObject(env, clazz);
    574     if (am == NULL) {
    575         return JNI_TRUE;
    576     }
    577     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
    578 }
    579 
    580 static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
    581 {
    582     Vector<String8> locales;
    583 
    584     AssetManager* am = assetManagerForJavaObject(env, clazz);
    585     if (am == NULL) {
    586         return NULL;
    587     }
    588 
    589     am->getLocales(&locales, includeSystemLocales);
    590 
    591     const int N = locales.size();
    592 
    593     jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
    594     if (result == NULL) {
    595         return NULL;
    596     }
    597 
    598     for (int i=0; i<N; i++) {
    599         jstring str = env->NewStringUTF(locales[i].string());
    600         if (str == NULL) {
    601             return NULL;
    602         }
    603         env->SetObjectArrayElement(result, i, str);
    604         env->DeleteLocalRef(str);
    605     }
    606 
    607     return result;
    608 }
    609 
    610 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
    611 {
    612     return getLocales(env, clazz, true /* include system locales */);
    613 }
    614 
    615 static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
    616 {
    617     return getLocales(env, clazz, false /* don't include system locales */);
    618 }
    619 
    620 static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
    621     jobject result = env->NewObject(gConfigurationOffsets.classObject,
    622             gConfigurationOffsets.constructor);
    623     if (result == NULL) {
    624         return NULL;
    625     }
    626 
    627     env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
    628             config.smallestScreenWidthDp);
    629     env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
    630     env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
    631 
    632     return result;
    633 }
    634 
    635 static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
    636         const Vector<ResTable_config>& configs) {
    637     const int N = configs.size();
    638     jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
    639     if (result == NULL) {
    640         return NULL;
    641     }
    642 
    643     for (int i=0; i<N; i++) {
    644         jobject config = constructConfigurationObject(env, configs[i]);
    645         if (config == NULL) {
    646             env->DeleteLocalRef(result);
    647             return NULL;
    648         }
    649 
    650         env->SetObjectArrayElement(result, i, config);
    651         env->DeleteLocalRef(config);
    652     }
    653 
    654     return result;
    655 }
    656 
    657 static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
    658     AssetManager* am = assetManagerForJavaObject(env, clazz);
    659     if (am == NULL) {
    660         return NULL;
    661     }
    662 
    663     const ResTable& res(am->getResources());
    664     Vector<ResTable_config> configs;
    665     res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
    666 
    667     return getSizeConfigurationsInternal(env, configs);
    668 }
    669 
    670 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
    671                                                           jint mcc, jint mnc,
    672                                                           jstring locale, jint orientation,
    673                                                           jint touchscreen, jint density,
    674                                                           jint keyboard, jint keyboardHidden,
    675                                                           jint navigation,
    676                                                           jint screenWidth, jint screenHeight,
    677                                                           jint smallestScreenWidthDp,
    678                                                           jint screenWidthDp, jint screenHeightDp,
    679                                                           jint screenLayout, jint uiMode,
    680                                                           jint colorMode, jint sdkVersion)
    681 {
    682     AssetManager* am = assetManagerForJavaObject(env, clazz);
    683     if (am == NULL) {
    684         return;
    685     }
    686 
    687     ResTable_config config;
    688     memset(&config, 0, sizeof(config));
    689 
    690     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
    691 
    692     // Constants duplicated from Java class android.content.res.Configuration.
    693     static const jint kScreenLayoutRoundMask = 0x300;
    694     static const jint kScreenLayoutRoundShift = 8;
    695 
    696     config.mcc = (uint16_t)mcc;
    697     config.mnc = (uint16_t)mnc;
    698     config.orientation = (uint8_t)orientation;
    699     config.touchscreen = (uint8_t)touchscreen;
    700     config.density = (uint16_t)density;
    701     config.keyboard = (uint8_t)keyboard;
    702     config.inputFlags = (uint8_t)keyboardHidden;
    703     config.navigation = (uint8_t)navigation;
    704     config.screenWidth = (uint16_t)screenWidth;
    705     config.screenHeight = (uint16_t)screenHeight;
    706     config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
    707     config.screenWidthDp = (uint16_t)screenWidthDp;
    708     config.screenHeightDp = (uint16_t)screenHeightDp;
    709     config.screenLayout = (uint8_t)screenLayout;
    710     config.uiMode = (uint8_t)uiMode;
    711     config.colorMode = (uint8_t)colorMode;
    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 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
   1114                                                           jlong themeToken,
   1115                                                           jint defStyleAttr,
   1116                                                           jint defStyleRes,
   1117                                                           jintArray inValues,
   1118                                                           jintArray attrs,
   1119                                                           jintArray outValues,
   1120                                                           jintArray outIndices)
   1121 {
   1122     if (themeToken == 0) {
   1123         jniThrowNullPointerException(env, "theme token");
   1124         return JNI_FALSE;
   1125     }
   1126     if (attrs == NULL) {
   1127         jniThrowNullPointerException(env, "attrs");
   1128         return JNI_FALSE;
   1129     }
   1130     if (outValues == NULL) {
   1131         jniThrowNullPointerException(env, "out values");
   1132         return JNI_FALSE;
   1133     }
   1134 
   1135     const jsize NI = env->GetArrayLength(attrs);
   1136     const jsize NV = env->GetArrayLength(outValues);
   1137     if (NV < (NI*STYLE_NUM_ENTRIES)) {
   1138         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
   1139         return JNI_FALSE;
   1140     }
   1141 
   1142     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
   1143     if (src == NULL) {
   1144         return JNI_FALSE;
   1145     }
   1146 
   1147     jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
   1148     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
   1149 
   1150     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1151     if (baseDest == NULL) {
   1152         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1153         return JNI_FALSE;
   1154     }
   1155 
   1156     jint* indices = NULL;
   1157     if (outIndices != NULL) {
   1158         if (env->GetArrayLength(outIndices) > NI) {
   1159             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
   1160         }
   1161     }
   1162 
   1163     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
   1164     bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
   1165                                (uint32_t*) srcValues, NSV,
   1166                                (uint32_t*) src, NI,
   1167                                (uint32_t*) baseDest,
   1168                                (uint32_t*) indices);
   1169 
   1170     if (indices != NULL) {
   1171         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
   1172     }
   1173     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1174     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
   1175     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1176     return result ? JNI_TRUE : JNI_FALSE;
   1177 }
   1178 
   1179 static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
   1180         jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
   1181         jlong outValuesAddress, jlong outIndicesAddress) {
   1182     jint* attrs = env->GetIntArrayElements(attrsObj, 0);
   1183     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
   1184     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
   1185     uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
   1186     uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
   1187     ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
   1188             reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
   1189     env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
   1190 }
   1191 
   1192 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
   1193                                                         jlong xmlParserToken,
   1194                                                         jintArray attrs,
   1195                                                         jintArray outValues,
   1196                                                         jintArray outIndices)
   1197 {
   1198     if (xmlParserToken == 0) {
   1199         jniThrowNullPointerException(env, "xmlParserToken");
   1200         return JNI_FALSE;
   1201     }
   1202     if (attrs == NULL) {
   1203         jniThrowNullPointerException(env, "attrs");
   1204         return JNI_FALSE;
   1205     }
   1206     if (outValues == NULL) {
   1207         jniThrowNullPointerException(env, "out values");
   1208         return JNI_FALSE;
   1209     }
   1210 
   1211     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1212     if (am == NULL) {
   1213         return JNI_FALSE;
   1214     }
   1215     const ResTable& res(am->getResources());
   1216     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
   1217 
   1218     const jsize NI = env->GetArrayLength(attrs);
   1219     const jsize NV = env->GetArrayLength(outValues);
   1220     if (NV < (NI*STYLE_NUM_ENTRIES)) {
   1221         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
   1222         return JNI_FALSE;
   1223     }
   1224 
   1225     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
   1226     if (src == NULL) {
   1227         return JNI_FALSE;
   1228     }
   1229 
   1230     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1231     if (baseDest == NULL) {
   1232         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1233         return JNI_FALSE;
   1234     }
   1235 
   1236     jint* indices = NULL;
   1237     if (outIndices != NULL) {
   1238         if (env->GetArrayLength(outIndices) > NI) {
   1239             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
   1240         }
   1241     }
   1242 
   1243     bool result = RetrieveAttributes(&res, xmlParser,
   1244                                      (uint32_t*) src, NI,
   1245                                      (uint32_t*) baseDest,
   1246                                      (uint32_t*) indices);
   1247 
   1248     if (indices != NULL) {
   1249         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
   1250     }
   1251     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1252     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
   1253     return result ? JNI_TRUE : JNI_FALSE;
   1254 }
   1255 
   1256 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
   1257                                                        jint id)
   1258 {
   1259     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1260     if (am == NULL) {
   1261         return 0;
   1262     }
   1263     const ResTable& res(am->getResources());
   1264 
   1265     res.lock();
   1266     const ResTable::bag_entry* defStyleEnt = NULL;
   1267     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
   1268     res.unlock();
   1269 
   1270     return static_cast<jint>(bagOff);
   1271 }
   1272 
   1273 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
   1274                                                         jint id,
   1275                                                         jintArray outValues)
   1276 {
   1277     if (outValues == NULL) {
   1278         jniThrowNullPointerException(env, "out values");
   1279         return JNI_FALSE;
   1280     }
   1281 
   1282     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1283     if (am == NULL) {
   1284         return JNI_FALSE;
   1285     }
   1286     const ResTable& res(am->getResources());
   1287     ResTable_config config;
   1288     Res_value value;
   1289     ssize_t block;
   1290 
   1291     const jsize NV = env->GetArrayLength(outValues);
   1292 
   1293     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
   1294     jint* dest = baseDest;
   1295     if (dest == NULL) {
   1296         jniThrowException(env, "java/lang/OutOfMemoryError", "");
   1297         return JNI_FALSE;
   1298     }
   1299 
   1300     // Now lock down the resource object and start pulling stuff from it.
   1301     res.lock();
   1302 
   1303     const ResTable::bag_entry* arrayEnt = NULL;
   1304     uint32_t arrayTypeSetFlags = 0;
   1305     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
   1306     const ResTable::bag_entry* endArrayEnt = arrayEnt +
   1307         (bagOff >= 0 ? bagOff : 0);
   1308 
   1309     int i = 0;
   1310     uint32_t typeSetFlags;
   1311     while (i < NV && arrayEnt < endArrayEnt) {
   1312         block = arrayEnt->stringBlock;
   1313         typeSetFlags = arrayTypeSetFlags;
   1314         config.density = 0;
   1315         value = arrayEnt->map.value;
   1316 
   1317         uint32_t resid = 0;
   1318         if (value.dataType != Res_value::TYPE_NULL) {
   1319             // Take care of resolving the found resource to its final value.
   1320             //printf("Resolving attribute reference\n");
   1321             ssize_t newBlock = res.resolveReference(&value, block, &resid,
   1322                     &typeSetFlags, &config);
   1323             if (kThrowOnBadId) {
   1324                 if (newBlock == BAD_INDEX) {
   1325                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1326                     return JNI_FALSE;
   1327                 }
   1328             }
   1329             if (newBlock >= 0) block = newBlock;
   1330         }
   1331 
   1332         // Deal with the special @null value -- it turns back to TYPE_NULL.
   1333         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
   1334             value.dataType = Res_value::TYPE_NULL;
   1335             value.data = Res_value::DATA_NULL_UNDEFINED;
   1336         }
   1337 
   1338         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
   1339 
   1340         // Write the final value back to Java.
   1341         dest[STYLE_TYPE] = value.dataType;
   1342         dest[STYLE_DATA] = value.data;
   1343         dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
   1344         dest[STYLE_RESOURCE_ID] = resid;
   1345         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
   1346         dest[STYLE_DENSITY] = config.density;
   1347         dest += STYLE_NUM_ENTRIES;
   1348         i+= STYLE_NUM_ENTRIES;
   1349         arrayEnt++;
   1350     }
   1351 
   1352     i /= STYLE_NUM_ENTRIES;
   1353 
   1354     res.unlock();
   1355 
   1356     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
   1357 
   1358     return i;
   1359 }
   1360 
   1361 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
   1362                                                          jint cookie,
   1363                                                          jstring fileName)
   1364 {
   1365     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1366     if (am == NULL) {
   1367         return 0;
   1368     }
   1369 
   1370     ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
   1371 
   1372     ScopedUtfChars fileName8(env, fileName);
   1373     if (fileName8.c_str() == NULL) {
   1374         return 0;
   1375     }
   1376 
   1377     int32_t assetCookie = static_cast<int32_t>(cookie);
   1378     Asset* a = assetCookie
   1379         ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
   1380         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
   1381 
   1382     if (a == NULL) {
   1383         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
   1384         return 0;
   1385     }
   1386 
   1387     const DynamicRefTable* dynamicRefTable =
   1388             am->getResources().getDynamicRefTableForCookie(assetCookie);
   1389     ResXMLTree* block = new ResXMLTree(dynamicRefTable);
   1390     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
   1391     a->close();
   1392     delete a;
   1393 
   1394     if (err != NO_ERROR) {
   1395         jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
   1396         return 0;
   1397     }
   1398 
   1399     return reinterpret_cast<jlong>(block);
   1400 }
   1401 
   1402 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
   1403                                                                  jint arrayResId)
   1404 {
   1405     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1406     if (am == NULL) {
   1407         return NULL;
   1408     }
   1409     const ResTable& res(am->getResources());
   1410 
   1411     const ResTable::bag_entry* startOfBag;
   1412     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1413     if (N < 0) {
   1414         return NULL;
   1415     }
   1416 
   1417     jintArray array = env->NewIntArray(N * 2);
   1418     if (array == NULL) {
   1419         res.unlockBag(startOfBag);
   1420         return NULL;
   1421     }
   1422 
   1423     Res_value value;
   1424     const ResTable::bag_entry* bag = startOfBag;
   1425     for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
   1426         jint stringIndex = -1;
   1427         jint stringBlock = 0;
   1428         value = bag->map.value;
   1429 
   1430         // Take care of resolving the found resource to its final value.
   1431         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
   1432         if (value.dataType == Res_value::TYPE_STRING) {
   1433             stringIndex = value.data;
   1434         }
   1435 
   1436         if (kThrowOnBadId) {
   1437             if (stringBlock == BAD_INDEX) {
   1438                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1439                 return array;
   1440             }
   1441         }
   1442 
   1443         //todo: It might be faster to allocate a C array to contain
   1444         //      the blocknums and indices, put them in there and then
   1445         //      do just one SetIntArrayRegion()
   1446         env->SetIntArrayRegion(array, j, 1, &stringBlock);
   1447         env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
   1448         j = j + 2;
   1449     }
   1450     res.unlockBag(startOfBag);
   1451     return array;
   1452 }
   1453 
   1454 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
   1455                                                                         jint arrayResId)
   1456 {
   1457     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1458     if (am == NULL) {
   1459         return NULL;
   1460     }
   1461     const ResTable& res(am->getResources());
   1462 
   1463     const ResTable::bag_entry* startOfBag;
   1464     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1465     if (N < 0) {
   1466         return NULL;
   1467     }
   1468 
   1469     jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
   1470     if (env->ExceptionCheck()) {
   1471         res.unlockBag(startOfBag);
   1472         return NULL;
   1473     }
   1474 
   1475     Res_value value;
   1476     const ResTable::bag_entry* bag = startOfBag;
   1477     size_t strLen = 0;
   1478     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1479         value = bag->map.value;
   1480         jstring str = NULL;
   1481 
   1482         // Take care of resolving the found resource to its final value.
   1483         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
   1484         if (kThrowOnBadId) {
   1485             if (block == BAD_INDEX) {
   1486                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1487                 return array;
   1488             }
   1489         }
   1490         if (value.dataType == Res_value::TYPE_STRING) {
   1491             const ResStringPool* pool = res.getTableStringBlock(block);
   1492             const char* str8 = pool->string8At(value.data, &strLen);
   1493             if (str8 != NULL) {
   1494                 str = env->NewStringUTF(str8);
   1495             } else {
   1496                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
   1497                 str = env->NewString(reinterpret_cast<const jchar*>(str16),
   1498                                      strLen);
   1499             }
   1500 
   1501             // If one of our NewString{UTF} calls failed due to memory, an
   1502             // exception will be pending.
   1503             if (env->ExceptionCheck()) {
   1504                 res.unlockBag(startOfBag);
   1505                 return NULL;
   1506             }
   1507 
   1508             env->SetObjectArrayElement(array, i, str);
   1509 
   1510             // str is not NULL at that point, otherwise ExceptionCheck would have been true.
   1511             // If we have a large amount of strings in our array, we might
   1512             // overflow the local reference table of the VM.
   1513             env->DeleteLocalRef(str);
   1514         }
   1515     }
   1516     res.unlockBag(startOfBag);
   1517     return array;
   1518 }
   1519 
   1520 static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
   1521                                                                         jint arrayResId)
   1522 {
   1523     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1524     if (am == NULL) {
   1525         return NULL;
   1526     }
   1527     const ResTable& res(am->getResources());
   1528 
   1529     const ResTable::bag_entry* startOfBag;
   1530     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
   1531     if (N < 0) {
   1532         return NULL;
   1533     }
   1534 
   1535     jintArray array = env->NewIntArray(N);
   1536     if (array == NULL) {
   1537         res.unlockBag(startOfBag);
   1538         return NULL;
   1539     }
   1540 
   1541     Res_value value;
   1542     const ResTable::bag_entry* bag = startOfBag;
   1543     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1544         value = bag->map.value;
   1545 
   1546         // Take care of resolving the found resource to its final value.
   1547         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
   1548         if (kThrowOnBadId) {
   1549             if (block == BAD_INDEX) {
   1550                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
   1551                 return array;
   1552             }
   1553         }
   1554         if (value.dataType >= Res_value::TYPE_FIRST_INT
   1555                 && value.dataType <= Res_value::TYPE_LAST_INT) {
   1556             int intVal = value.data;
   1557             env->SetIntArrayRegion(array, i, 1, &intVal);
   1558         }
   1559     }
   1560     res.unlockBag(startOfBag);
   1561     return array;
   1562 }
   1563 
   1564 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
   1565                                                                  jint styleId)
   1566 {
   1567     AssetManager* am = assetManagerForJavaObject(env, clazz);
   1568     if (am == NULL) {
   1569         return NULL;
   1570     }
   1571     const ResTable& res(am->getResources());
   1572 
   1573     const ResTable::bag_entry* startOfBag;
   1574     const ssize_t N = res.lockBag(styleId, &startOfBag);
   1575     if (N < 0) {
   1576         return NULL;
   1577     }
   1578 
   1579     jintArray array = env->NewIntArray(N);
   1580     if (array == NULL) {
   1581         res.unlockBag(startOfBag);
   1582         return NULL;
   1583     }
   1584 
   1585     const ResTable::bag_entry* bag = startOfBag;
   1586     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
   1587         int resourceId = bag->map.name.ident;
   1588         env->SetIntArrayRegion(array, i, 1, &resourceId);
   1589     }
   1590     res.unlockBag(startOfBag);
   1591     return array;
   1592 }
   1593 
   1594 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
   1595 {
   1596     if (isSystem) {
   1597         verifySystemIdmaps();
   1598     }
   1599     AssetManager* am = new AssetManager();
   1600     if (am == NULL) {
   1601         jniThrowException(env, "java/lang/OutOfMemoryError", "");
   1602         return;
   1603     }
   1604 
   1605     am->addDefaultAssets();
   1606 
   1607     ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
   1608     env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
   1609 }
   1610 
   1611 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
   1612 {
   1613     AssetManager* am = (AssetManager*)
   1614         (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
   1615     ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
   1616     if (am != NULL) {
   1617         delete am;
   1618         env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
   1619     }
   1620 }
   1621 
   1622 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
   1623 {
   1624     return Asset::getGlobalCount();
   1625 }
   1626 
   1627 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
   1628 {
   1629     String8 alloc = Asset::getAssetAllocations();
   1630     if (alloc.length() <= 0) {
   1631         return NULL;
   1632     }
   1633 
   1634     jstring str = env->NewStringUTF(alloc.string());
   1635     return str;
   1636 }
   1637 
   1638 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
   1639 {
   1640     return AssetManager::getGlobalCount();
   1641 }
   1642 
   1643 // ----------------------------------------------------------------------------
   1644 
   1645 /*
   1646  * JNI registration.
   1647  */
   1648 static const JNINativeMethod gAssetManagerMethods[] = {
   1649     /* name, signature, funcPtr */
   1650 
   1651     // Basic asset stuff.
   1652     { "openAsset",      "(Ljava/lang/String;I)J",
   1653         (void*) android_content_AssetManager_openAsset },
   1654     { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1655         (void*) android_content_AssetManager_openAssetFd },
   1656     { "openNonAssetNative", "(ILjava/lang/String;I)J",
   1657         (void*) android_content_AssetManager_openNonAssetNative },
   1658     { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
   1659         (void*) android_content_AssetManager_openNonAssetFdNative },
   1660     { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
   1661         (void*) android_content_AssetManager_list },
   1662     { "destroyAsset",   "(J)V",
   1663         (void*) android_content_AssetManager_destroyAsset },
   1664     { "readAssetChar",  "(J)I",
   1665         (void*) android_content_AssetManager_readAssetChar },
   1666     { "readAsset",      "(J[BII)I",
   1667         (void*) android_content_AssetManager_readAsset },
   1668     { "seekAsset",      "(JJI)J",
   1669         (void*) android_content_AssetManager_seekAsset },
   1670     { "getAssetLength", "(J)J",
   1671         (void*) android_content_AssetManager_getAssetLength },
   1672     { "getAssetRemainingLength", "(J)J",
   1673         (void*) android_content_AssetManager_getAssetRemainingLength },
   1674     { "addAssetPathNative", "(Ljava/lang/String;Z)I",
   1675         (void*) android_content_AssetManager_addAssetPath },
   1676     { "addOverlayPathNative",   "(Ljava/lang/String;)I",
   1677         (void*) android_content_AssetManager_addOverlayPath },
   1678     { "isUpToDate",     "()Z",
   1679         (void*) android_content_AssetManager_isUpToDate },
   1680 
   1681     // Resources.
   1682     { "getLocales",      "()[Ljava/lang/String;",
   1683         (void*) android_content_AssetManager_getLocales },
   1684     { "getNonSystemLocales", "()[Ljava/lang/String;",
   1685         (void*) android_content_AssetManager_getNonSystemLocales },
   1686     { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
   1687         (void*) android_content_AssetManager_getSizeConfigurations },
   1688     { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
   1689         (void*) android_content_AssetManager_setConfiguration },
   1690     { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
   1691         (void*) android_content_AssetManager_getResourceIdentifier },
   1692     { "getResourceName","(I)Ljava/lang/String;",
   1693         (void*) android_content_AssetManager_getResourceName },
   1694     { "getResourcePackageName","(I)Ljava/lang/String;",
   1695         (void*) android_content_AssetManager_getResourcePackageName },
   1696     { "getResourceTypeName","(I)Ljava/lang/String;",
   1697         (void*) android_content_AssetManager_getResourceTypeName },
   1698     { "getResourceEntryName","(I)Ljava/lang/String;",
   1699         (void*) android_content_AssetManager_getResourceEntryName },
   1700     { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
   1701         (void*) android_content_AssetManager_loadResourceValue },
   1702     { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
   1703         (void*) android_content_AssetManager_loadResourceBagValue },
   1704     { "getStringBlockCount","()I",
   1705         (void*) android_content_AssetManager_getStringBlockCount },
   1706     { "getNativeStringBlock","(I)J",
   1707         (void*) android_content_AssetManager_getNativeStringBlock },
   1708     { "getCookieName","(I)Ljava/lang/String;",
   1709         (void*) android_content_AssetManager_getCookieName },
   1710     { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
   1711         (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
   1712 
   1713     // Themes.
   1714     { "newTheme", "()J",
   1715         (void*) android_content_AssetManager_newTheme },
   1716     { "deleteTheme", "(J)V",
   1717         (void*) android_content_AssetManager_deleteTheme },
   1718     { "applyThemeStyle", "(JIZ)V",
   1719         (void*) android_content_AssetManager_applyThemeStyle },
   1720     { "copyTheme", "(JJ)V",
   1721         (void*) android_content_AssetManager_copyTheme },
   1722     { "clearTheme", "(J)V",
   1723         (void*) android_content_AssetManager_clearTheme },
   1724     { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
   1725         (void*) android_content_AssetManager_loadThemeAttributeValue },
   1726     { "getThemeChangingConfigurations", "(J)I",
   1727         (void*) android_content_AssetManager_getThemeChangingConfigurations },
   1728     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
   1729         (void*) android_content_AssetManager_dumpTheme },
   1730     { "applyStyle","(JIIJ[IIJJ)V",
   1731         (void*) android_content_AssetManager_applyStyle },
   1732     { "resolveAttrs","(JII[I[I[I[I)Z",
   1733         (void*) android_content_AssetManager_resolveAttrs },
   1734     { "retrieveAttributes","(J[I[I[I)Z",
   1735         (void*) android_content_AssetManager_retrieveAttributes },
   1736     { "getArraySize","(I)I",
   1737         (void*) android_content_AssetManager_getArraySize },
   1738     { "retrieveArray","(I[I)I",
   1739         (void*) android_content_AssetManager_retrieveArray },
   1740 
   1741     // XML files.
   1742     { "openXmlAssetNative", "(ILjava/lang/String;)J",
   1743         (void*) android_content_AssetManager_openXmlAssetNative },
   1744 
   1745     // Arrays.
   1746     { "getArrayStringResource","(I)[Ljava/lang/String;",
   1747         (void*) android_content_AssetManager_getArrayStringResource },
   1748     { "getArrayStringInfo","(I)[I",
   1749         (void*) android_content_AssetManager_getArrayStringInfo },
   1750     { "getArrayIntResource","(I)[I",
   1751         (void*) android_content_AssetManager_getArrayIntResource },
   1752     { "getStyleAttributes","(I)[I",
   1753         (void*) android_content_AssetManager_getStyleAttributes },
   1754 
   1755     // Bookkeeping.
   1756     { "init",           "(Z)V",
   1757         (void*) android_content_AssetManager_init },
   1758     { "destroy",        "()V",
   1759         (void*) android_content_AssetManager_destroy },
   1760     { "getGlobalAssetCount", "()I",
   1761         (void*) android_content_AssetManager_getGlobalAssetCount },
   1762     { "getAssetAllocations", "()Ljava/lang/String;",
   1763         (void*) android_content_AssetManager_getAssetAllocations },
   1764     { "getGlobalAssetManagerCount", "()I",
   1765         (void*) android_content_AssetManager_getGlobalAssetManagerCount },
   1766 };
   1767 
   1768 int register_android_content_AssetManager(JNIEnv* env)
   1769 {
   1770     jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
   1771     gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
   1772     gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
   1773     gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
   1774                                                  "Ljava/lang/CharSequence;");
   1775     gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
   1776     gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
   1777     gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
   1778                                                                  "changingConfigurations", "I");
   1779     gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
   1780 
   1781     jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
   1782     gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
   1783                                                       "Landroid/os/ParcelFileDescriptor;");
   1784     gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
   1785     gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
   1786 
   1787     jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
   1788     gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
   1789 
   1790     jclass stringClass = FindClassOrDie(env, "java/lang/String");
   1791     g_stringClass = MakeGlobalRefOrDie(env, stringClass);
   1792 
   1793     jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
   1794     gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
   1795     gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
   1796                                                        "<init>", "()V");
   1797     gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
   1798                                                "(ILjava/lang/Object;)V");
   1799 
   1800     jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
   1801     gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
   1802     gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
   1803             "<init>", "()V");
   1804     gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
   1805             "smallestScreenWidthDp", "I");
   1806     gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
   1807             "screenWidthDp", "I");
   1808     gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
   1809             "screenHeightDp", "I");
   1810 
   1811     return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
   1812                                 NELEM(gAssetManagerMethods));
   1813 }
   1814 
   1815 }; // namespace android
   1816