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