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