android_util_AssetManager.cpp revision 11bdd5b10b5f921b657283fa94463263171218d5
1/* //device/libs/android_runtime/android_util_AssetManager.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "asset"
19
20#include <android_runtime/android_util_AssetManager.h>
21
22#include "jni.h"
23#include "JNIHelp.h"
24#include "ScopedStringChars.h"
25#include "ScopedUtfChars.h"
26#include "android_util_Binder.h"
27#include <utils/misc.h>
28#include <android_runtime/AndroidRuntime.h>
29#include <utils/Log.h>
30
31#include <androidfw/Asset.h>
32#include <androidfw/AssetManager.h>
33#include <androidfw/AttributeFinder.h>
34#include <androidfw/ResourceTypes.h>
35
36#include <private/android_filesystem_config.h> // for AID_SYSTEM
37
38#include <stdio.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41
42#include <linux/capability.h>
43extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
44extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
45
46
47namespace android {
48
49static const bool kThrowOnBadId = false;
50static const bool kDebugStyles = false;
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 (kThrowOnBadId) {
808        if (block == BAD_INDEX) {
809            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
810            return 0;
811        }
812    }
813    uint32_t ref = ident;
814    if (resolve) {
815        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
816        if (kThrowOnBadId) {
817            if (block == BAD_INDEX) {
818                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
819                return 0;
820            }
821        }
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 (kThrowOnBadId) {
868            if (block == BAD_INDEX) {
869                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
870                return 0;
871            }
872        }
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 (kThrowOnBadId) {
983            if (block == BAD_INDEX) {
984                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
985                return 0;
986            }
987        }
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    (void)res;
999
1000    // XXX Need to use params.
1001    theme->dumpToLog();
1002}
1003
1004class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1005public:
1006    XmlAttributeFinder(const ResXMLParser* parser)
1007        : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1008        , mParser(parser) {}
1009
1010    inline uint32_t getAttribute(jsize index) const {
1011        return mParser->getAttributeNameResID(index);
1012    }
1013
1014private:
1015    const ResXMLParser* mParser;
1016};
1017
1018class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1019public:
1020    BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1021        : BackTrackingAttributeFinder(start, end) {}
1022
1023    inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1024        return entry->map.name.ident;
1025    }
1026};
1027
1028static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1029                                                          jlong themeToken,
1030                                                          jint defStyleAttr,
1031                                                          jint defStyleRes,
1032                                                          jintArray inValues,
1033                                                          jintArray attrs,
1034                                                          jintArray outValues,
1035                                                          jintArray outIndices)
1036{
1037    if (themeToken == 0) {
1038        jniThrowNullPointerException(env, "theme token");
1039        return JNI_FALSE;
1040    }
1041    if (attrs == NULL) {
1042        jniThrowNullPointerException(env, "attrs");
1043        return JNI_FALSE;
1044    }
1045    if (outValues == NULL) {
1046        jniThrowNullPointerException(env, "out values");
1047        return JNI_FALSE;
1048    }
1049
1050    if (kDebugStyles) {
1051        ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
1052                themeToken, defStyleAttr, defStyleRes);
1053    }
1054
1055    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1056    const ResTable& res = theme->getResTable();
1057    ResTable_config config;
1058    Res_value value;
1059
1060    const jsize NI = env->GetArrayLength(attrs);
1061    const jsize NV = env->GetArrayLength(outValues);
1062    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1063        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1064        return JNI_FALSE;
1065    }
1066
1067    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1068    if (src == NULL) {
1069        return JNI_FALSE;
1070    }
1071
1072    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1073    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1074
1075    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1076    jint* dest = baseDest;
1077    if (dest == NULL) {
1078        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1079        return JNI_FALSE;
1080    }
1081
1082    jint* indices = NULL;
1083    int indicesIdx = 0;
1084    if (outIndices != NULL) {
1085        if (env->GetArrayLength(outIndices) > NI) {
1086            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1087        }
1088    }
1089
1090    // Load default style from attribute, if specified...
1091    uint32_t defStyleBagTypeSetFlags = 0;
1092    if (defStyleAttr != 0) {
1093        Res_value value;
1094        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1095            if (value.dataType == Res_value::TYPE_REFERENCE) {
1096                defStyleRes = value.data;
1097            }
1098        }
1099    }
1100
1101    // Now lock down the resource object and start pulling stuff from it.
1102    res.lock();
1103
1104    // Retrieve the default style bag, if requested.
1105    const ResTable::bag_entry* defStyleStart = NULL;
1106    uint32_t defStyleTypeSetFlags = 0;
1107    ssize_t bagOff = defStyleRes != 0
1108            ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1109    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1110    const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1111    BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1112
1113    // Now iterate through all of the attributes that the client has requested,
1114    // filling in each with whatever data we can find.
1115    ssize_t block = 0;
1116    uint32_t typeSetFlags;
1117    for (jsize ii=0; ii<NI; ii++) {
1118        const uint32_t curIdent = (uint32_t)src[ii];
1119
1120        if (kDebugStyles) {
1121            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1122        }
1123
1124        // Try to find a value for this attribute...  we prioritize values
1125        // coming from, first XML attributes, then XML style, then default
1126        // style, and finally the theme.
1127        value.dataType = Res_value::TYPE_NULL;
1128        value.data = Res_value::DATA_NULL_UNDEFINED;
1129        typeSetFlags = 0;
1130        config.density = 0;
1131
1132        // Retrieve the current input value if available.
1133        if (NSV > 0 && srcValues[ii] != 0) {
1134            block = -1;
1135            value.dataType = Res_value::TYPE_ATTRIBUTE;
1136            value.data = srcValues[ii];
1137            if (kDebugStyles) {
1138                ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1139            }
1140        }
1141
1142        if (value.dataType == Res_value::TYPE_NULL) {
1143            const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1144            if (defStyleEntry != defStyleEnd) {
1145                block = defStyleEntry->stringBlock;
1146                typeSetFlags = defStyleTypeSetFlags;
1147                value = defStyleEntry->map.value;
1148                if (kDebugStyles) {
1149                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1150                }
1151            }
1152        }
1153
1154        uint32_t resid = 0;
1155        if (value.dataType != Res_value::TYPE_NULL) {
1156            // Take care of resolving the found resource to its final value.
1157            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1158                    &resid, &typeSetFlags, &config);
1159            if (newBlock >= 0) block = newBlock;
1160            if (kDebugStyles) {
1161                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1162            }
1163        } else {
1164            // If we still don't have a value for this attribute, try to find
1165            // it in the theme!
1166            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1167            if (newBlock >= 0) {
1168                if (kDebugStyles) {
1169                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1170                }
1171                newBlock = res.resolveReference(&value, block, &resid,
1172                        &typeSetFlags, &config);
1173                if (kThrowOnBadId) {
1174                    if (newBlock == BAD_INDEX) {
1175                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1176                        return JNI_FALSE;
1177                    }
1178                }
1179                if (newBlock >= 0) block = newBlock;
1180                if (kDebugStyles) {
1181                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1182                }
1183            }
1184        }
1185
1186        // Deal with the special @null value -- it turns back to TYPE_NULL.
1187        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1188            if (kDebugStyles) {
1189                ALOGI("-> Setting to @null!");
1190            }
1191            value.dataType = Res_value::TYPE_NULL;
1192            value.data = Res_value::DATA_NULL_UNDEFINED;
1193            block = -1;
1194        }
1195
1196        if (kDebugStyles) {
1197            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1198                  value.data);
1199        }
1200
1201        // Write the final value back to Java.
1202        dest[STYLE_TYPE] = value.dataType;
1203        dest[STYLE_DATA] = value.data;
1204        dest[STYLE_ASSET_COOKIE] =
1205            block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1206        dest[STYLE_RESOURCE_ID] = resid;
1207        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1208        dest[STYLE_DENSITY] = config.density;
1209
1210        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1211            indicesIdx++;
1212            indices[indicesIdx] = ii;
1213        }
1214
1215        dest += STYLE_NUM_ENTRIES;
1216    }
1217
1218    res.unlock();
1219
1220    if (indices != NULL) {
1221        indices[0] = indicesIdx;
1222        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1223    }
1224    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1225    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1226    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1227
1228    return JNI_TRUE;
1229}
1230
1231static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1232                                                        jlong themeToken,
1233                                                        jint defStyleAttr,
1234                                                        jint defStyleRes,
1235                                                        jlong xmlParserToken,
1236                                                        jintArray attrs,
1237                                                        jintArray outValues,
1238                                                        jintArray outIndices)
1239{
1240    if (themeToken == 0) {
1241        jniThrowNullPointerException(env, "theme token");
1242        return JNI_FALSE;
1243    }
1244    if (attrs == NULL) {
1245        jniThrowNullPointerException(env, "attrs");
1246        return JNI_FALSE;
1247    }
1248    if (outValues == NULL) {
1249        jniThrowNullPointerException(env, "out values");
1250        return JNI_FALSE;
1251    }
1252
1253    if (kDebugStyles) {
1254    ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
1255          themeToken, defStyleAttr, defStyleRes, xmlParserToken);
1256    }
1257
1258    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1259    const ResTable& res = theme->getResTable();
1260    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1261    ResTable_config config;
1262    Res_value value;
1263
1264    const jsize NI = env->GetArrayLength(attrs);
1265    const jsize NV = env->GetArrayLength(outValues);
1266    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1267        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1268        return JNI_FALSE;
1269    }
1270
1271    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1272    if (src == NULL) {
1273        return JNI_FALSE;
1274    }
1275
1276    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1277    jint* dest = baseDest;
1278    if (dest == NULL) {
1279        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1280        return JNI_FALSE;
1281    }
1282
1283    jint* indices = NULL;
1284    int indicesIdx = 0;
1285    if (outIndices != NULL) {
1286        if (env->GetArrayLength(outIndices) > NI) {
1287            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1288        }
1289    }
1290
1291    // Load default style from attribute, if specified...
1292    uint32_t defStyleBagTypeSetFlags = 0;
1293    if (defStyleAttr != 0) {
1294        Res_value value;
1295        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1296            if (value.dataType == Res_value::TYPE_REFERENCE) {
1297                defStyleRes = value.data;
1298            }
1299        }
1300    }
1301
1302    // Retrieve the style class associated with the current XML tag.
1303    int style = 0;
1304    uint32_t styleBagTypeSetFlags = 0;
1305    if (xmlParser != NULL) {
1306        ssize_t idx = xmlParser->indexOfStyle();
1307        if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1308            if (value.dataType == value.TYPE_ATTRIBUTE) {
1309                if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1310                    value.dataType = Res_value::TYPE_NULL;
1311                }
1312            }
1313            if (value.dataType == value.TYPE_REFERENCE) {
1314                style = value.data;
1315            }
1316        }
1317    }
1318
1319    // Now lock down the resource object and start pulling stuff from it.
1320    res.lock();
1321
1322    // Retrieve the default style bag, if requested.
1323    const ResTable::bag_entry* defStyleAttrStart = NULL;
1324    uint32_t defStyleTypeSetFlags = 0;
1325    ssize_t bagOff = defStyleRes != 0
1326            ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1327    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1328    const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1329    BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1330
1331    // Retrieve the style class bag, if requested.
1332    const ResTable::bag_entry* styleAttrStart = NULL;
1333    uint32_t styleTypeSetFlags = 0;
1334    bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1335    styleTypeSetFlags |= styleBagTypeSetFlags;
1336    const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1337    BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1338
1339    // Retrieve the XML attributes, if requested.
1340    static const ssize_t kXmlBlock = 0x10000000;
1341    XmlAttributeFinder xmlAttrFinder(xmlParser);
1342    const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1343
1344    // Now iterate through all of the attributes that the client has requested,
1345    // filling in each with whatever data we can find.
1346    ssize_t block = 0;
1347    uint32_t typeSetFlags;
1348    for (jsize ii = 0; ii < NI; ii++) {
1349        const uint32_t curIdent = (uint32_t)src[ii];
1350
1351        if (kDebugStyles) {
1352            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1353        }
1354
1355        // Try to find a value for this attribute...  we prioritize values
1356        // coming from, first XML attributes, then XML style, then default
1357        // style, and finally the theme.
1358        value.dataType = Res_value::TYPE_NULL;
1359        value.data = Res_value::DATA_NULL_UNDEFINED;
1360        typeSetFlags = 0;
1361        config.density = 0;
1362
1363        // Walk through the xml attributes looking for the requested attribute.
1364        const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1365        if (xmlAttrIdx != xmlAttrEnd) {
1366            // We found the attribute we were looking for.
1367            block = kXmlBlock;
1368            xmlParser->getAttributeValue(xmlAttrIdx, &value);
1369            if (kDebugStyles) {
1370                ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1371            }
1372        }
1373
1374        if (value.dataType == Res_value::TYPE_NULL) {
1375            // Walk through the style class values looking for the requested attribute.
1376            const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1377            if (styleAttrEntry != styleAttrEnd) {
1378                // We found the attribute we were looking for.
1379                block = styleAttrEntry->stringBlock;
1380                typeSetFlags = styleTypeSetFlags;
1381                value = styleAttrEntry->map.value;
1382                if (kDebugStyles) {
1383                    ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1384                }
1385            }
1386        }
1387
1388        if (value.dataType == Res_value::TYPE_NULL) {
1389            // Walk through the default style values looking for the requested attribute.
1390            const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1391            if (defStyleAttrEntry != defStyleAttrEnd) {
1392                // We found the attribute we were looking for.
1393                block = defStyleAttrEntry->stringBlock;
1394                typeSetFlags = styleTypeSetFlags;
1395                value = defStyleAttrEntry->map.value;
1396                if (kDebugStyles) {
1397                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1398                }
1399            }
1400        }
1401
1402        uint32_t resid = 0;
1403        if (value.dataType != Res_value::TYPE_NULL) {
1404            // Take care of resolving the found resource to its final value.
1405            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1406                    &resid, &typeSetFlags, &config);
1407            if (newBlock >= 0) {
1408                block = newBlock;
1409            }
1410
1411            if (kDebugStyles) {
1412                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1413            }
1414        } else {
1415            // If we still don't have a value for this attribute, try to find
1416            // it in the theme!
1417            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1418            if (newBlock >= 0) {
1419                if (kDebugStyles) {
1420                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1421                }
1422                newBlock = res.resolveReference(&value, block, &resid,
1423                        &typeSetFlags, &config);
1424                if (kThrowOnBadId) {
1425                    if (newBlock == BAD_INDEX) {
1426                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1427                        return JNI_FALSE;
1428                    }
1429                }
1430
1431                if (newBlock >= 0) {
1432                    block = newBlock;
1433                }
1434
1435                if (kDebugStyles) {
1436                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1437                }
1438            }
1439        }
1440
1441        // Deal with the special @null value -- it turns back to TYPE_NULL.
1442        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1443            if (kDebugStyles) {
1444                ALOGI("-> Setting to @null!");
1445            }
1446            value.dataType = Res_value::TYPE_NULL;
1447            value.data = Res_value::DATA_NULL_UNDEFINED;
1448            block = kXmlBlock;
1449        }
1450
1451        if (kDebugStyles) {
1452            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1453        }
1454
1455        // Write the final value back to Java.
1456        dest[STYLE_TYPE] = value.dataType;
1457        dest[STYLE_DATA] = value.data;
1458        dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1459            static_cast<jint>(res.getTableCookie(block)) : -1;
1460        dest[STYLE_RESOURCE_ID] = resid;
1461        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1462        dest[STYLE_DENSITY] = config.density;
1463
1464        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1465            indicesIdx++;
1466            indices[indicesIdx] = ii;
1467        }
1468
1469        dest += STYLE_NUM_ENTRIES;
1470    }
1471
1472    res.unlock();
1473
1474    if (indices != NULL) {
1475        indices[0] = indicesIdx;
1476        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1477    }
1478    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1479    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1480
1481    return JNI_TRUE;
1482}
1483
1484static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1485                                                        jlong xmlParserToken,
1486                                                        jintArray attrs,
1487                                                        jintArray outValues,
1488                                                        jintArray outIndices)
1489{
1490    if (xmlParserToken == 0) {
1491        jniThrowNullPointerException(env, "xmlParserToken");
1492        return JNI_FALSE;
1493    }
1494    if (attrs == NULL) {
1495        jniThrowNullPointerException(env, "attrs");
1496        return JNI_FALSE;
1497    }
1498    if (outValues == NULL) {
1499        jniThrowNullPointerException(env, "out values");
1500        return JNI_FALSE;
1501    }
1502
1503    AssetManager* am = assetManagerForJavaObject(env, clazz);
1504    if (am == NULL) {
1505        return JNI_FALSE;
1506    }
1507    const ResTable& res(am->getResources());
1508    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1509    ResTable_config config;
1510    Res_value value;
1511
1512    const jsize NI = env->GetArrayLength(attrs);
1513    const jsize NV = env->GetArrayLength(outValues);
1514    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1515        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1516        return JNI_FALSE;
1517    }
1518
1519    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1520    if (src == NULL) {
1521        return JNI_FALSE;
1522    }
1523
1524    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1525    jint* dest = baseDest;
1526    if (dest == NULL) {
1527        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1528        return JNI_FALSE;
1529    }
1530
1531    jint* indices = NULL;
1532    int indicesIdx = 0;
1533    if (outIndices != NULL) {
1534        if (env->GetArrayLength(outIndices) > NI) {
1535            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1536        }
1537    }
1538
1539    // Now lock down the resource object and start pulling stuff from it.
1540    res.lock();
1541
1542    // Retrieve the XML attributes, if requested.
1543    const jsize NX = xmlParser->getAttributeCount();
1544    jsize ix=0;
1545    uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1546
1547    static const ssize_t kXmlBlock = 0x10000000;
1548
1549    // Now iterate through all of the attributes that the client has requested,
1550    // filling in each with whatever data we can find.
1551    ssize_t block = 0;
1552    uint32_t typeSetFlags;
1553    for (jsize ii=0; ii<NI; ii++) {
1554        const uint32_t curIdent = (uint32_t)src[ii];
1555
1556        // Try to find a value for this attribute...
1557        value.dataType = Res_value::TYPE_NULL;
1558        value.data = Res_value::DATA_NULL_UNDEFINED;
1559        typeSetFlags = 0;
1560        config.density = 0;
1561
1562        // Skip through XML attributes until the end or the next possible match.
1563        while (ix < NX && curIdent > curXmlAttr) {
1564            ix++;
1565            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1566        }
1567        // Retrieve the current XML attribute if it matches, and step to next.
1568        if (ix < NX && curIdent == curXmlAttr) {
1569            block = kXmlBlock;
1570            xmlParser->getAttributeValue(ix, &value);
1571            ix++;
1572            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1573        }
1574
1575        //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1576        uint32_t resid = 0;
1577        if (value.dataType != Res_value::TYPE_NULL) {
1578            // Take care of resolving the found resource to its final value.
1579            //printf("Resolving attribute reference\n");
1580            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1581                    &typeSetFlags, &config);
1582            if (kThrowOnBadId) {
1583                if (newBlock == BAD_INDEX) {
1584                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1585                    return JNI_FALSE;
1586                }
1587            }
1588            if (newBlock >= 0) block = newBlock;
1589        }
1590
1591        // Deal with the special @null value -- it turns back to TYPE_NULL.
1592        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1593            value.dataType = Res_value::TYPE_NULL;
1594            value.data = Res_value::DATA_NULL_UNDEFINED;
1595        }
1596
1597        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1598
1599        // Write the final value back to Java.
1600        dest[STYLE_TYPE] = value.dataType;
1601        dest[STYLE_DATA] = value.data;
1602        dest[STYLE_ASSET_COOKIE] =
1603            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1604        dest[STYLE_RESOURCE_ID] = resid;
1605        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1606        dest[STYLE_DENSITY] = config.density;
1607
1608        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1609            indicesIdx++;
1610            indices[indicesIdx] = ii;
1611        }
1612
1613        dest += STYLE_NUM_ENTRIES;
1614    }
1615
1616    res.unlock();
1617
1618    if (indices != NULL) {
1619        indices[0] = indicesIdx;
1620        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1621    }
1622
1623    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1624    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1625
1626    return JNI_TRUE;
1627}
1628
1629static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1630                                                       jint id)
1631{
1632    AssetManager* am = assetManagerForJavaObject(env, clazz);
1633    if (am == NULL) {
1634        return 0;
1635    }
1636    const ResTable& res(am->getResources());
1637
1638    res.lock();
1639    const ResTable::bag_entry* defStyleEnt = NULL;
1640    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1641    res.unlock();
1642
1643    return static_cast<jint>(bagOff);
1644}
1645
1646static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1647                                                        jint id,
1648                                                        jintArray outValues)
1649{
1650    if (outValues == NULL) {
1651        jniThrowNullPointerException(env, "out values");
1652        return JNI_FALSE;
1653    }
1654
1655    AssetManager* am = assetManagerForJavaObject(env, clazz);
1656    if (am == NULL) {
1657        return JNI_FALSE;
1658    }
1659    const ResTable& res(am->getResources());
1660    ResTable_config config;
1661    Res_value value;
1662    ssize_t block;
1663
1664    const jsize NV = env->GetArrayLength(outValues);
1665
1666    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1667    jint* dest = baseDest;
1668    if (dest == NULL) {
1669        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1670        return JNI_FALSE;
1671    }
1672
1673    // Now lock down the resource object and start pulling stuff from it.
1674    res.lock();
1675
1676    const ResTable::bag_entry* arrayEnt = NULL;
1677    uint32_t arrayTypeSetFlags = 0;
1678    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1679    const ResTable::bag_entry* endArrayEnt = arrayEnt +
1680        (bagOff >= 0 ? bagOff : 0);
1681
1682    int i = 0;
1683    uint32_t typeSetFlags;
1684    while (i < NV && arrayEnt < endArrayEnt) {
1685        block = arrayEnt->stringBlock;
1686        typeSetFlags = arrayTypeSetFlags;
1687        config.density = 0;
1688        value = arrayEnt->map.value;
1689
1690        uint32_t resid = 0;
1691        if (value.dataType != Res_value::TYPE_NULL) {
1692            // Take care of resolving the found resource to its final value.
1693            //printf("Resolving attribute reference\n");
1694            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1695                    &typeSetFlags, &config);
1696            if (kThrowOnBadId) {
1697                if (newBlock == BAD_INDEX) {
1698                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1699                    return JNI_FALSE;
1700                }
1701            }
1702            if (newBlock >= 0) block = newBlock;
1703        }
1704
1705        // Deal with the special @null value -- it turns back to TYPE_NULL.
1706        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1707            value.dataType = Res_value::TYPE_NULL;
1708            value.data = Res_value::DATA_NULL_UNDEFINED;
1709        }
1710
1711        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1712
1713        // Write the final value back to Java.
1714        dest[STYLE_TYPE] = value.dataType;
1715        dest[STYLE_DATA] = value.data;
1716        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1717        dest[STYLE_RESOURCE_ID] = resid;
1718        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1719        dest[STYLE_DENSITY] = config.density;
1720        dest += STYLE_NUM_ENTRIES;
1721        i+= STYLE_NUM_ENTRIES;
1722        arrayEnt++;
1723    }
1724
1725    i /= STYLE_NUM_ENTRIES;
1726
1727    res.unlock();
1728
1729    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1730
1731    return i;
1732}
1733
1734static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1735                                                         jint cookie,
1736                                                         jstring fileName)
1737{
1738    AssetManager* am = assetManagerForJavaObject(env, clazz);
1739    if (am == NULL) {
1740        return 0;
1741    }
1742
1743    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1744
1745    ScopedUtfChars fileName8(env, fileName);
1746    if (fileName8.c_str() == NULL) {
1747        return 0;
1748    }
1749
1750    int32_t assetCookie = static_cast<int32_t>(cookie);
1751    Asset* a = assetCookie
1752        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1753        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1754
1755    if (a == NULL) {
1756        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1757        return 0;
1758    }
1759
1760    const DynamicRefTable* dynamicRefTable =
1761            am->getResources().getDynamicRefTableForCookie(assetCookie);
1762    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1763    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1764    a->close();
1765    delete a;
1766
1767    if (err != NO_ERROR) {
1768        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1769        return 0;
1770    }
1771
1772    return reinterpret_cast<jlong>(block);
1773}
1774
1775static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1776                                                                 jint arrayResId)
1777{
1778    AssetManager* am = assetManagerForJavaObject(env, clazz);
1779    if (am == NULL) {
1780        return NULL;
1781    }
1782    const ResTable& res(am->getResources());
1783
1784    const ResTable::bag_entry* startOfBag;
1785    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1786    if (N < 0) {
1787        return NULL;
1788    }
1789
1790    jintArray array = env->NewIntArray(N * 2);
1791    if (array == NULL) {
1792        res.unlockBag(startOfBag);
1793        return NULL;
1794    }
1795
1796    Res_value value;
1797    const ResTable::bag_entry* bag = startOfBag;
1798    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1799        jint stringIndex = -1;
1800        jint stringBlock = 0;
1801        value = bag->map.value;
1802
1803        // Take care of resolving the found resource to its final value.
1804        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1805        if (value.dataType == Res_value::TYPE_STRING) {
1806            stringIndex = value.data;
1807        }
1808
1809        if (kThrowOnBadId) {
1810            if (stringBlock == BAD_INDEX) {
1811                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1812                return array;
1813            }
1814        }
1815
1816        //todo: It might be faster to allocate a C array to contain
1817        //      the blocknums and indices, put them in there and then
1818        //      do just one SetIntArrayRegion()
1819        env->SetIntArrayRegion(array, j, 1, &stringBlock);
1820        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1821        j = j + 2;
1822    }
1823    res.unlockBag(startOfBag);
1824    return array;
1825}
1826
1827static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1828                                                                        jint arrayResId)
1829{
1830    AssetManager* am = assetManagerForJavaObject(env, clazz);
1831    if (am == NULL) {
1832        return NULL;
1833    }
1834    const ResTable& res(am->getResources());
1835
1836    const ResTable::bag_entry* startOfBag;
1837    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1838    if (N < 0) {
1839        return NULL;
1840    }
1841
1842    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1843    if (env->ExceptionCheck()) {
1844        res.unlockBag(startOfBag);
1845        return NULL;
1846    }
1847
1848    Res_value value;
1849    const ResTable::bag_entry* bag = startOfBag;
1850    size_t strLen = 0;
1851    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1852        value = bag->map.value;
1853        jstring str = NULL;
1854
1855        // Take care of resolving the found resource to its final value.
1856        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1857        if (kThrowOnBadId) {
1858            if (block == BAD_INDEX) {
1859                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1860                return array;
1861            }
1862        }
1863        if (value.dataType == Res_value::TYPE_STRING) {
1864            const ResStringPool* pool = res.getTableStringBlock(block);
1865            const char* str8 = pool->string8At(value.data, &strLen);
1866            if (str8 != NULL) {
1867                str = env->NewStringUTF(str8);
1868            } else {
1869                const char16_t* str16 = pool->stringAt(value.data, &strLen);
1870                str = env->NewString(str16, strLen);
1871            }
1872
1873            // If one of our NewString{UTF} calls failed due to memory, an
1874            // exception will be pending.
1875            if (env->ExceptionCheck()) {
1876                res.unlockBag(startOfBag);
1877                return NULL;
1878            }
1879
1880            env->SetObjectArrayElement(array, i, str);
1881
1882            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1883            // If we have a large amount of strings in our array, we might
1884            // overflow the local reference table of the VM.
1885            env->DeleteLocalRef(str);
1886        }
1887    }
1888    res.unlockBag(startOfBag);
1889    return array;
1890}
1891
1892static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1893                                                                        jint arrayResId)
1894{
1895    AssetManager* am = assetManagerForJavaObject(env, clazz);
1896    if (am == NULL) {
1897        return NULL;
1898    }
1899    const ResTable& res(am->getResources());
1900
1901    const ResTable::bag_entry* startOfBag;
1902    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1903    if (N < 0) {
1904        return NULL;
1905    }
1906
1907    jintArray array = env->NewIntArray(N);
1908    if (array == NULL) {
1909        res.unlockBag(startOfBag);
1910        return NULL;
1911    }
1912
1913    Res_value value;
1914    const ResTable::bag_entry* bag = startOfBag;
1915    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1916        value = bag->map.value;
1917
1918        // Take care of resolving the found resource to its final value.
1919        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1920        if (kThrowOnBadId) {
1921            if (block == BAD_INDEX) {
1922                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1923                return array;
1924            }
1925        }
1926        if (value.dataType >= Res_value::TYPE_FIRST_INT
1927                && value.dataType <= Res_value::TYPE_LAST_INT) {
1928            int intVal = value.data;
1929            env->SetIntArrayRegion(array, i, 1, &intVal);
1930        }
1931    }
1932    res.unlockBag(startOfBag);
1933    return array;
1934}
1935
1936static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1937                                                                 jint styleId)
1938{
1939    AssetManager* am = assetManagerForJavaObject(env, clazz);
1940    if (am == NULL) {
1941        return NULL;
1942    }
1943    const ResTable& res(am->getResources());
1944
1945    const ResTable::bag_entry* startOfBag;
1946    const ssize_t N = res.lockBag(styleId, &startOfBag);
1947    if (N < 0) {
1948        return NULL;
1949    }
1950
1951    jintArray array = env->NewIntArray(N);
1952    if (array == NULL) {
1953        res.unlockBag(startOfBag);
1954        return NULL;
1955    }
1956
1957    const ResTable::bag_entry* bag = startOfBag;
1958    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1959        int resourceId = bag->map.name.ident;
1960        env->SetIntArrayRegion(array, i, 1, &resourceId);
1961    }
1962    res.unlockBag(startOfBag);
1963    return array;
1964}
1965
1966static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1967{
1968    if (isSystem) {
1969        verifySystemIdmaps();
1970    }
1971    AssetManager* am = new AssetManager();
1972    if (am == NULL) {
1973        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1974        return;
1975    }
1976
1977    am->addDefaultAssets();
1978
1979    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1980    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1981}
1982
1983static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1984{
1985    AssetManager* am = (AssetManager*)
1986        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1987    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1988    if (am != NULL) {
1989        delete am;
1990        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
1991    }
1992}
1993
1994static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1995{
1996    return Asset::getGlobalCount();
1997}
1998
1999static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2000{
2001    String8 alloc = Asset::getAssetAllocations();
2002    if (alloc.length() <= 0) {
2003        return NULL;
2004    }
2005
2006    jstring str = env->NewStringUTF(alloc.string());
2007    return str;
2008}
2009
2010static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2011{
2012    return AssetManager::getGlobalCount();
2013}
2014
2015// ----------------------------------------------------------------------------
2016
2017/*
2018 * JNI registration.
2019 */
2020static JNINativeMethod gAssetManagerMethods[] = {
2021    /* name, signature, funcPtr */
2022
2023    // Basic asset stuff.
2024    { "openAsset",      "(Ljava/lang/String;I)J",
2025        (void*) android_content_AssetManager_openAsset },
2026    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2027        (void*) android_content_AssetManager_openAssetFd },
2028    { "openNonAssetNative", "(ILjava/lang/String;I)J",
2029        (void*) android_content_AssetManager_openNonAssetNative },
2030    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2031        (void*) android_content_AssetManager_openNonAssetFdNative },
2032    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
2033        (void*) android_content_AssetManager_list },
2034    { "destroyAsset",   "(J)V",
2035        (void*) android_content_AssetManager_destroyAsset },
2036    { "readAssetChar",  "(J)I",
2037        (void*) android_content_AssetManager_readAssetChar },
2038    { "readAsset",      "(J[BII)I",
2039        (void*) android_content_AssetManager_readAsset },
2040    { "seekAsset",      "(JJI)J",
2041        (void*) android_content_AssetManager_seekAsset },
2042    { "getAssetLength", "(J)J",
2043        (void*) android_content_AssetManager_getAssetLength },
2044    { "getAssetRemainingLength", "(J)J",
2045        (void*) android_content_AssetManager_getAssetRemainingLength },
2046    { "addAssetPathNative", "(Ljava/lang/String;)I",
2047        (void*) android_content_AssetManager_addAssetPath },
2048    { "addOverlayPath",   "(Ljava/lang/String;)I",
2049        (void*) android_content_AssetManager_addOverlayPath },
2050    { "isUpToDate",     "()Z",
2051        (void*) android_content_AssetManager_isUpToDate },
2052
2053    // Resources.
2054    { "setLocale",      "(Ljava/lang/String;)V",
2055        (void*) android_content_AssetManager_setLocale },
2056    { "getLocales",      "()[Ljava/lang/String;",
2057        (void*) android_content_AssetManager_getLocales },
2058    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2059        (void*) android_content_AssetManager_setConfiguration },
2060    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2061        (void*) android_content_AssetManager_getResourceIdentifier },
2062    { "getResourceName","(I)Ljava/lang/String;",
2063        (void*) android_content_AssetManager_getResourceName },
2064    { "getResourcePackageName","(I)Ljava/lang/String;",
2065        (void*) android_content_AssetManager_getResourcePackageName },
2066    { "getResourceTypeName","(I)Ljava/lang/String;",
2067        (void*) android_content_AssetManager_getResourceTypeName },
2068    { "getResourceEntryName","(I)Ljava/lang/String;",
2069        (void*) android_content_AssetManager_getResourceEntryName },
2070    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2071        (void*) android_content_AssetManager_loadResourceValue },
2072    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2073        (void*) android_content_AssetManager_loadResourceBagValue },
2074    { "getStringBlockCount","()I",
2075        (void*) android_content_AssetManager_getStringBlockCount },
2076    { "getNativeStringBlock","(I)J",
2077        (void*) android_content_AssetManager_getNativeStringBlock },
2078    { "getCookieName","(I)Ljava/lang/String;",
2079        (void*) android_content_AssetManager_getCookieName },
2080    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2081        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2082
2083    // Themes.
2084    { "newTheme", "()J",
2085        (void*) android_content_AssetManager_newTheme },
2086    { "deleteTheme", "(J)V",
2087        (void*) android_content_AssetManager_deleteTheme },
2088    { "applyThemeStyle", "(JIZ)V",
2089        (void*) android_content_AssetManager_applyThemeStyle },
2090    { "copyTheme", "(JJ)V",
2091        (void*) android_content_AssetManager_copyTheme },
2092    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2093        (void*) android_content_AssetManager_loadThemeAttributeValue },
2094    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2095        (void*) android_content_AssetManager_dumpTheme },
2096    { "applyStyle","(JIIJ[I[I[I)Z",
2097        (void*) android_content_AssetManager_applyStyle },
2098    { "resolveAttrs","(JII[I[I[I[I)Z",
2099        (void*) android_content_AssetManager_resolveAttrs },
2100    { "retrieveAttributes","(J[I[I[I)Z",
2101        (void*) android_content_AssetManager_retrieveAttributes },
2102    { "getArraySize","(I)I",
2103        (void*) android_content_AssetManager_getArraySize },
2104    { "retrieveArray","(I[I)I",
2105        (void*) android_content_AssetManager_retrieveArray },
2106
2107    // XML files.
2108    { "openXmlAssetNative", "(ILjava/lang/String;)J",
2109        (void*) android_content_AssetManager_openXmlAssetNative },
2110
2111    // Arrays.
2112    { "getArrayStringResource","(I)[Ljava/lang/String;",
2113        (void*) android_content_AssetManager_getArrayStringResource },
2114    { "getArrayStringInfo","(I)[I",
2115        (void*) android_content_AssetManager_getArrayStringInfo },
2116    { "getArrayIntResource","(I)[I",
2117        (void*) android_content_AssetManager_getArrayIntResource },
2118    { "getStyleAttributes","(I)[I",
2119        (void*) android_content_AssetManager_getStyleAttributes },
2120
2121    // Bookkeeping.
2122    { "init",           "(Z)V",
2123        (void*) android_content_AssetManager_init },
2124    { "destroy",        "()V",
2125        (void*) android_content_AssetManager_destroy },
2126    { "getGlobalAssetCount", "()I",
2127        (void*) android_content_AssetManager_getGlobalAssetCount },
2128    { "getAssetAllocations", "()Ljava/lang/String;",
2129        (void*) android_content_AssetManager_getAssetAllocations },
2130    { "getGlobalAssetManagerCount", "()I",
2131        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2132};
2133
2134int register_android_content_AssetManager(JNIEnv* env)
2135{
2136    jclass typedValue = env->FindClass("android/util/TypedValue");
2137    LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
2138    gTypedValueOffsets.mType
2139        = env->GetFieldID(typedValue, "type", "I");
2140    LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
2141    gTypedValueOffsets.mData
2142        = env->GetFieldID(typedValue, "data", "I");
2143    LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
2144    gTypedValueOffsets.mString
2145        = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
2146    LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
2147    gTypedValueOffsets.mAssetCookie
2148        = env->GetFieldID(typedValue, "assetCookie", "I");
2149    LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
2150    gTypedValueOffsets.mResourceId
2151        = env->GetFieldID(typedValue, "resourceId", "I");
2152    LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
2153    gTypedValueOffsets.mChangingConfigurations
2154        = env->GetFieldID(typedValue, "changingConfigurations", "I");
2155    LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
2156    gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
2157    LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
2158
2159    jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
2160    LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
2161    gAssetFileDescriptorOffsets.mFd
2162        = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
2163    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
2164    gAssetFileDescriptorOffsets.mStartOffset
2165        = env->GetFieldID(assetFd, "mStartOffset", "J");
2166    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
2167    gAssetFileDescriptorOffsets.mLength
2168        = env->GetFieldID(assetFd, "mLength", "J");
2169    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
2170
2171    jclass assetManager = env->FindClass("android/content/res/AssetManager");
2172    LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
2173    gAssetManagerOffsets.mObject
2174        = env->GetFieldID(assetManager, "mObject", "J");
2175    LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
2176
2177    jclass stringClass = env->FindClass("java/lang/String");
2178    LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
2179    g_stringClass = (jclass)env->NewGlobalRef(stringClass);
2180    LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
2181
2182    jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
2183    LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
2184    gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
2185    gSparseArrayOffsets.constructor =
2186            env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
2187    LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
2188    gSparseArrayOffsets.put =
2189            env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
2190    LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
2191
2192    return AndroidRuntime::registerNativeMethods(env,
2193            "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
2194}
2195
2196}; // namespace android
2197