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