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