android_util_AssetManager.cpp revision 042ad633bc68bdda2bb0c50216706d73575a5992
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        while (ix < NX && curIdent > curXmlAttr) {
1328            ix++;
1329            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1330        }
1331        // Retrieve the current XML attribute if it matches, and step to next.
1332        if (ix < NX && curIdent == curXmlAttr) {
1333            block = kXmlBlock;
1334            xmlParser->getAttributeValue(ix, &value);
1335            ix++;
1336            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1337            DEBUG_STYLES(ALOGI("-> From XML: type=0x%x, data=0x%08x",
1338                    value.dataType, value.data));
1339        }
1340
1341        // Skip through the style values until the end or the next possible match.
1342        while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1343            styleEnt++;
1344        }
1345        // Retrieve the current style attribute if it matches, and step to next.
1346        if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1347            if (value.dataType == Res_value::TYPE_NULL) {
1348                block = styleEnt->stringBlock;
1349                typeSetFlags = styleTypeSetFlags;
1350                value = styleEnt->map.value;
1351                DEBUG_STYLES(ALOGI("-> From style: type=0x%x, data=0x%08x",
1352                        value.dataType, value.data));
1353            }
1354            styleEnt++;
1355        }
1356
1357        // Skip through the default style values until the end or the next possible match.
1358        while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1359            defStyleEnt++;
1360        }
1361        // Retrieve the current default style attribute if it matches, and step to next.
1362        if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1363            if (value.dataType == Res_value::TYPE_NULL) {
1364                block = defStyleEnt->stringBlock;
1365                typeSetFlags = defStyleTypeSetFlags;
1366                value = defStyleEnt->map.value;
1367                DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
1368                        value.dataType, value.data));
1369            }
1370            defStyleEnt++;
1371        }
1372
1373        uint32_t resid = 0;
1374        if (value.dataType != Res_value::TYPE_NULL) {
1375            // Take care of resolving the found resource to its final value.
1376            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1377                    &resid, &typeSetFlags, &config);
1378            if (newBlock >= 0) block = newBlock;
1379            DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1380                    value.dataType, value.data));
1381        } else {
1382            // If we still don't have a value for this attribute, try to find
1383            // it in the theme!
1384            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1385            if (newBlock >= 0) {
1386                DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
1387                        value.dataType, value.data));
1388                newBlock = res.resolveReference(&value, block, &resid,
1389                        &typeSetFlags, &config);
1390#if THROW_ON_BAD_ID
1391                if (newBlock == BAD_INDEX) {
1392                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1393                    return JNI_FALSE;
1394                }
1395#endif
1396                if (newBlock >= 0) block = newBlock;
1397                DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1398                        value.dataType, value.data));
1399            }
1400        }
1401
1402        // Deal with the special @null value -- it turns back to TYPE_NULL.
1403        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1404            DEBUG_STYLES(ALOGI("-> Setting to @null!"));
1405            value.dataType = Res_value::TYPE_NULL;
1406            block = kXmlBlock;
1407        }
1408
1409        DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1410                curIdent, value.dataType, value.data));
1411
1412        // Write the final value back to Java.
1413        dest[STYLE_TYPE] = value.dataType;
1414        dest[STYLE_DATA] = value.data;
1415        dest[STYLE_ASSET_COOKIE] =
1416            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1417        dest[STYLE_RESOURCE_ID] = resid;
1418        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1419        dest[STYLE_DENSITY] = config.density;
1420
1421        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1422            indicesIdx++;
1423            indices[indicesIdx] = ii;
1424        }
1425
1426        dest += STYLE_NUM_ENTRIES;
1427    }
1428
1429    res.unlock();
1430
1431    if (indices != NULL) {
1432        indices[0] = indicesIdx;
1433        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1434    }
1435    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1436    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1437
1438    return JNI_TRUE;
1439}
1440
1441static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1442                                                        jlong xmlParserToken,
1443                                                        jintArray attrs,
1444                                                        jintArray outValues,
1445                                                        jintArray outIndices)
1446{
1447    if (xmlParserToken == 0) {
1448        jniThrowNullPointerException(env, "xmlParserToken");
1449        return JNI_FALSE;
1450    }
1451    if (attrs == NULL) {
1452        jniThrowNullPointerException(env, "attrs");
1453        return JNI_FALSE;
1454    }
1455    if (outValues == NULL) {
1456        jniThrowNullPointerException(env, "out values");
1457        return JNI_FALSE;
1458    }
1459
1460    AssetManager* am = assetManagerForJavaObject(env, clazz);
1461    if (am == NULL) {
1462        return JNI_FALSE;
1463    }
1464    const ResTable& res(am->getResources());
1465    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1466    ResTable_config config;
1467    Res_value value;
1468
1469    const jsize NI = env->GetArrayLength(attrs);
1470    const jsize NV = env->GetArrayLength(outValues);
1471    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1472        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1473        return JNI_FALSE;
1474    }
1475
1476    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1477    if (src == NULL) {
1478        return JNI_FALSE;
1479    }
1480
1481    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1482    jint* dest = baseDest;
1483    if (dest == NULL) {
1484        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1485        return JNI_FALSE;
1486    }
1487
1488    jint* indices = NULL;
1489    int indicesIdx = 0;
1490    if (outIndices != NULL) {
1491        if (env->GetArrayLength(outIndices) > NI) {
1492            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1493        }
1494    }
1495
1496    // Now lock down the resource object and start pulling stuff from it.
1497    res.lock();
1498
1499    // Retrieve the XML attributes, if requested.
1500    const jsize NX = xmlParser->getAttributeCount();
1501    jsize ix=0;
1502    uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1503
1504    static const ssize_t kXmlBlock = 0x10000000;
1505
1506    // Now iterate through all of the attributes that the client has requested,
1507    // filling in each with whatever data we can find.
1508    ssize_t block = 0;
1509    uint32_t typeSetFlags;
1510    for (jsize ii=0; ii<NI; ii++) {
1511        const uint32_t curIdent = (uint32_t)src[ii];
1512
1513        // Try to find a value for this attribute...
1514        value.dataType = Res_value::TYPE_NULL;
1515        value.data = 0;
1516        typeSetFlags = 0;
1517        config.density = 0;
1518
1519        // Skip through XML attributes until the end or the next possible match.
1520        while (ix < NX && curIdent > curXmlAttr) {
1521            ix++;
1522            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1523        }
1524        // Retrieve the current XML attribute if it matches, and step to next.
1525        if (ix < NX && curIdent == curXmlAttr) {
1526            block = kXmlBlock;
1527            xmlParser->getAttributeValue(ix, &value);
1528            ix++;
1529            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1530        }
1531
1532        //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1533        uint32_t resid = 0;
1534        if (value.dataType != Res_value::TYPE_NULL) {
1535            // Take care of resolving the found resource to its final value.
1536            //printf("Resolving attribute reference\n");
1537            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1538                    &typeSetFlags, &config);
1539#if THROW_ON_BAD_ID
1540            if (newBlock == BAD_INDEX) {
1541                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1542                return JNI_FALSE;
1543            }
1544#endif
1545            if (newBlock >= 0) block = newBlock;
1546        }
1547
1548        // Deal with the special @null value -- it turns back to TYPE_NULL.
1549        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1550            value.dataType = Res_value::TYPE_NULL;
1551        }
1552
1553        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1554
1555        // Write the final value back to Java.
1556        dest[STYLE_TYPE] = value.dataType;
1557        dest[STYLE_DATA] = value.data;
1558        dest[STYLE_ASSET_COOKIE] =
1559            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1560        dest[STYLE_RESOURCE_ID] = resid;
1561        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1562        dest[STYLE_DENSITY] = config.density;
1563
1564        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1565            indicesIdx++;
1566            indices[indicesIdx] = ii;
1567        }
1568
1569        dest += STYLE_NUM_ENTRIES;
1570    }
1571
1572    res.unlock();
1573
1574    if (indices != NULL) {
1575        indices[0] = indicesIdx;
1576        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1577    }
1578
1579    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1580    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1581
1582    return JNI_TRUE;
1583}
1584
1585static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1586                                                       jint id)
1587{
1588    AssetManager* am = assetManagerForJavaObject(env, clazz);
1589    if (am == NULL) {
1590        return 0;
1591    }
1592    const ResTable& res(am->getResources());
1593
1594    res.lock();
1595    const ResTable::bag_entry* defStyleEnt = NULL;
1596    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1597    res.unlock();
1598
1599    return static_cast<jint>(bagOff);
1600}
1601
1602static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1603                                                        jint id,
1604                                                        jintArray outValues)
1605{
1606    if (outValues == NULL) {
1607        jniThrowNullPointerException(env, "out values");
1608        return JNI_FALSE;
1609    }
1610
1611    AssetManager* am = assetManagerForJavaObject(env, clazz);
1612    if (am == NULL) {
1613        return JNI_FALSE;
1614    }
1615    const ResTable& res(am->getResources());
1616    ResTable_config config;
1617    Res_value value;
1618    ssize_t block;
1619
1620    const jsize NV = env->GetArrayLength(outValues);
1621
1622    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1623    jint* dest = baseDest;
1624    if (dest == NULL) {
1625        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1626        return JNI_FALSE;
1627    }
1628
1629    // Now lock down the resource object and start pulling stuff from it.
1630    res.lock();
1631
1632    const ResTable::bag_entry* arrayEnt = NULL;
1633    uint32_t arrayTypeSetFlags = 0;
1634    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1635    const ResTable::bag_entry* endArrayEnt = arrayEnt +
1636        (bagOff >= 0 ? bagOff : 0);
1637
1638    int i = 0;
1639    uint32_t typeSetFlags;
1640    while (i < NV && arrayEnt < endArrayEnt) {
1641        block = arrayEnt->stringBlock;
1642        typeSetFlags = arrayTypeSetFlags;
1643        config.density = 0;
1644        value = arrayEnt->map.value;
1645
1646        uint32_t resid = 0;
1647        if (value.dataType != Res_value::TYPE_NULL) {
1648            // Take care of resolving the found resource to its final value.
1649            //printf("Resolving attribute reference\n");
1650            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1651                    &typeSetFlags, &config);
1652#if THROW_ON_BAD_ID
1653            if (newBlock == BAD_INDEX) {
1654                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1655                return JNI_FALSE;
1656            }
1657#endif
1658            if (newBlock >= 0) block = newBlock;
1659        }
1660
1661        // Deal with the special @null value -- it turns back to TYPE_NULL.
1662        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1663            value.dataType = Res_value::TYPE_NULL;
1664        }
1665
1666        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1667
1668        // Write the final value back to Java.
1669        dest[STYLE_TYPE] = value.dataType;
1670        dest[STYLE_DATA] = value.data;
1671        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1672        dest[STYLE_RESOURCE_ID] = resid;
1673        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1674        dest[STYLE_DENSITY] = config.density;
1675        dest += STYLE_NUM_ENTRIES;
1676        i+= STYLE_NUM_ENTRIES;
1677        arrayEnt++;
1678    }
1679
1680    i /= STYLE_NUM_ENTRIES;
1681
1682    res.unlock();
1683
1684    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1685
1686    return i;
1687}
1688
1689static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1690                                                         jint cookie,
1691                                                         jstring fileName)
1692{
1693    AssetManager* am = assetManagerForJavaObject(env, clazz);
1694    if (am == NULL) {
1695        return 0;
1696    }
1697
1698    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1699
1700    ScopedUtfChars fileName8(env, fileName);
1701    if (fileName8.c_str() == NULL) {
1702        return 0;
1703    }
1704
1705    int32_t assetCookie = static_cast<int32_t>(cookie);
1706    Asset* a = assetCookie
1707        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1708        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1709
1710    if (a == NULL) {
1711        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1712        return 0;
1713    }
1714
1715    const DynamicRefTable* dynamicRefTable =
1716            am->getResources().getDynamicRefTableForCookie(assetCookie);
1717    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1718    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1719    a->close();
1720    delete a;
1721
1722    if (err != NO_ERROR) {
1723        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1724        return 0;
1725    }
1726
1727    return reinterpret_cast<jlong>(block);
1728}
1729
1730static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1731                                                                 jint arrayResId)
1732{
1733    AssetManager* am = assetManagerForJavaObject(env, clazz);
1734    if (am == NULL) {
1735        return NULL;
1736    }
1737    const ResTable& res(am->getResources());
1738
1739    const ResTable::bag_entry* startOfBag;
1740    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1741    if (N < 0) {
1742        return NULL;
1743    }
1744
1745    jintArray array = env->NewIntArray(N * 2);
1746    if (array == NULL) {
1747        res.unlockBag(startOfBag);
1748        return NULL;
1749    }
1750
1751    Res_value value;
1752    const ResTable::bag_entry* bag = startOfBag;
1753    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1754        jint stringIndex = -1;
1755        jint stringBlock = 0;
1756        value = bag->map.value;
1757
1758        // Take care of resolving the found resource to its final value.
1759        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1760        if (value.dataType == Res_value::TYPE_STRING) {
1761            stringIndex = value.data;
1762        }
1763
1764#if THROW_ON_BAD_ID
1765        if (stringBlock == BAD_INDEX) {
1766            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1767            return array;
1768        }
1769#endif
1770
1771        //todo: It might be faster to allocate a C array to contain
1772        //      the blocknums and indices, put them in there and then
1773        //      do just one SetIntArrayRegion()
1774        env->SetIntArrayRegion(array, j, 1, &stringBlock);
1775        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1776        j = j + 2;
1777    }
1778    res.unlockBag(startOfBag);
1779    return array;
1780}
1781
1782static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1783                                                                        jint arrayResId)
1784{
1785    AssetManager* am = assetManagerForJavaObject(env, clazz);
1786    if (am == NULL) {
1787        return NULL;
1788    }
1789    const ResTable& res(am->getResources());
1790
1791    const ResTable::bag_entry* startOfBag;
1792    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1793    if (N < 0) {
1794        return NULL;
1795    }
1796
1797    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1798    if (env->ExceptionCheck()) {
1799        res.unlockBag(startOfBag);
1800        return NULL;
1801    }
1802
1803    Res_value value;
1804    const ResTable::bag_entry* bag = startOfBag;
1805    size_t strLen = 0;
1806    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1807        value = bag->map.value;
1808        jstring str = NULL;
1809
1810        // Take care of resolving the found resource to its final value.
1811        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1812#if THROW_ON_BAD_ID
1813        if (block == BAD_INDEX) {
1814            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1815            return array;
1816        }
1817#endif
1818        if (value.dataType == Res_value::TYPE_STRING) {
1819            const ResStringPool* pool = res.getTableStringBlock(block);
1820            const char* str8 = pool->string8At(value.data, &strLen);
1821            if (str8 != NULL) {
1822                str = env->NewStringUTF(str8);
1823            } else {
1824                const char16_t* str16 = pool->stringAt(value.data, &strLen);
1825                str = env->NewString(str16, strLen);
1826            }
1827
1828            // If one of our NewString{UTF} calls failed due to memory, an
1829            // exception will be pending.
1830            if (env->ExceptionCheck()) {
1831                res.unlockBag(startOfBag);
1832                return NULL;
1833            }
1834
1835            env->SetObjectArrayElement(array, i, str);
1836
1837            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1838            // If we have a large amount of strings in our array, we might
1839            // overflow the local reference table of the VM.
1840            env->DeleteLocalRef(str);
1841        }
1842    }
1843    res.unlockBag(startOfBag);
1844    return array;
1845}
1846
1847static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1848                                                                        jint arrayResId)
1849{
1850    AssetManager* am = assetManagerForJavaObject(env, clazz);
1851    if (am == NULL) {
1852        return NULL;
1853    }
1854    const ResTable& res(am->getResources());
1855
1856    const ResTable::bag_entry* startOfBag;
1857    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1858    if (N < 0) {
1859        return NULL;
1860    }
1861
1862    jintArray array = env->NewIntArray(N);
1863    if (array == NULL) {
1864        res.unlockBag(startOfBag);
1865        return NULL;
1866    }
1867
1868    Res_value value;
1869    const ResTable::bag_entry* bag = startOfBag;
1870    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1871        value = bag->map.value;
1872
1873        // Take care of resolving the found resource to its final value.
1874        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1875#if THROW_ON_BAD_ID
1876        if (block == BAD_INDEX) {
1877            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1878            return array;
1879        }
1880#endif
1881        if (value.dataType >= Res_value::TYPE_FIRST_INT
1882                && value.dataType <= Res_value::TYPE_LAST_INT) {
1883            int intVal = value.data;
1884            env->SetIntArrayRegion(array, i, 1, &intVal);
1885        }
1886    }
1887    res.unlockBag(startOfBag);
1888    return array;
1889}
1890
1891static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1892                                                                 jint styleId)
1893{
1894    AssetManager* am = assetManagerForJavaObject(env, clazz);
1895    if (am == NULL) {
1896        return NULL;
1897    }
1898    const ResTable& res(am->getResources());
1899
1900    const ResTable::bag_entry* startOfBag;
1901    const ssize_t N = res.lockBag(styleId, &startOfBag);
1902    if (N < 0) {
1903        return NULL;
1904    }
1905
1906    jintArray array = env->NewIntArray(N);
1907    if (array == NULL) {
1908        res.unlockBag(startOfBag);
1909        return NULL;
1910    }
1911
1912    Res_value value;
1913    const ResTable::bag_entry* bag = startOfBag;
1914    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1915        int resourceId = bag->map.name.ident;
1916        env->SetIntArrayRegion(array, i, 1, &resourceId);
1917    }
1918    res.unlockBag(startOfBag);
1919    return array;
1920}
1921
1922static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1923{
1924    if (isSystem) {
1925        verifySystemIdmaps();
1926    }
1927    AssetManager* am = new AssetManager();
1928    if (am == NULL) {
1929        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1930        return;
1931    }
1932
1933    am->addDefaultAssets();
1934
1935    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1936    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1937}
1938
1939static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1940{
1941    AssetManager* am = (AssetManager*)
1942        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1943    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1944    if (am != NULL) {
1945        delete am;
1946        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
1947    }
1948}
1949
1950static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1951{
1952    return Asset::getGlobalCount();
1953}
1954
1955static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1956{
1957    String8 alloc = Asset::getAssetAllocations();
1958    if (alloc.length() <= 0) {
1959        return NULL;
1960    }
1961
1962    jstring str = env->NewStringUTF(alloc.string());
1963    return str;
1964}
1965
1966static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1967{
1968    return AssetManager::getGlobalCount();
1969}
1970
1971// ----------------------------------------------------------------------------
1972
1973/*
1974 * JNI registration.
1975 */
1976static JNINativeMethod gAssetManagerMethods[] = {
1977    /* name, signature, funcPtr */
1978
1979    // Basic asset stuff.
1980    { "openAsset",      "(Ljava/lang/String;I)J",
1981        (void*) android_content_AssetManager_openAsset },
1982    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1983        (void*) android_content_AssetManager_openAssetFd },
1984    { "openNonAssetNative", "(ILjava/lang/String;I)J",
1985        (void*) android_content_AssetManager_openNonAssetNative },
1986    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1987        (void*) android_content_AssetManager_openNonAssetFdNative },
1988    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
1989        (void*) android_content_AssetManager_list },
1990    { "destroyAsset",   "(J)V",
1991        (void*) android_content_AssetManager_destroyAsset },
1992    { "readAssetChar",  "(J)I",
1993        (void*) android_content_AssetManager_readAssetChar },
1994    { "readAsset",      "(J[BII)I",
1995        (void*) android_content_AssetManager_readAsset },
1996    { "seekAsset",      "(JJI)J",
1997        (void*) android_content_AssetManager_seekAsset },
1998    { "getAssetLength", "(J)J",
1999        (void*) android_content_AssetManager_getAssetLength },
2000    { "getAssetRemainingLength", "(J)J",
2001        (void*) android_content_AssetManager_getAssetRemainingLength },
2002    { "addAssetPathNative", "(Ljava/lang/String;)I",
2003        (void*) android_content_AssetManager_addAssetPath },
2004    { "addOverlayPath",   "(Ljava/lang/String;)I",
2005        (void*) android_content_AssetManager_addOverlayPath },
2006    { "isUpToDate",     "()Z",
2007        (void*) android_content_AssetManager_isUpToDate },
2008
2009    // Resources.
2010    { "setLocale",      "(Ljava/lang/String;)V",
2011        (void*) android_content_AssetManager_setLocale },
2012    { "getLocales",      "()[Ljava/lang/String;",
2013        (void*) android_content_AssetManager_getLocales },
2014    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2015        (void*) android_content_AssetManager_setConfiguration },
2016    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2017        (void*) android_content_AssetManager_getResourceIdentifier },
2018    { "getResourceName","(I)Ljava/lang/String;",
2019        (void*) android_content_AssetManager_getResourceName },
2020    { "getResourcePackageName","(I)Ljava/lang/String;",
2021        (void*) android_content_AssetManager_getResourcePackageName },
2022    { "getResourceTypeName","(I)Ljava/lang/String;",
2023        (void*) android_content_AssetManager_getResourceTypeName },
2024    { "getResourceEntryName","(I)Ljava/lang/String;",
2025        (void*) android_content_AssetManager_getResourceEntryName },
2026    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2027        (void*) android_content_AssetManager_loadResourceValue },
2028    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2029        (void*) android_content_AssetManager_loadResourceBagValue },
2030    { "getStringBlockCount","()I",
2031        (void*) android_content_AssetManager_getStringBlockCount },
2032    { "getNativeStringBlock","(I)J",
2033        (void*) android_content_AssetManager_getNativeStringBlock },
2034    { "getCookieName","(I)Ljava/lang/String;",
2035        (void*) android_content_AssetManager_getCookieName },
2036    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2037        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2038
2039    // Themes.
2040    { "newTheme", "()J",
2041        (void*) android_content_AssetManager_newTheme },
2042    { "deleteTheme", "(J)V",
2043        (void*) android_content_AssetManager_deleteTheme },
2044    { "applyThemeStyle", "(JIZ)V",
2045        (void*) android_content_AssetManager_applyThemeStyle },
2046    { "copyTheme", "(JJ)V",
2047        (void*) android_content_AssetManager_copyTheme },
2048    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2049        (void*) android_content_AssetManager_loadThemeAttributeValue },
2050    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2051        (void*) android_content_AssetManager_dumpTheme },
2052    { "applyStyle","(JIIJ[I[I[I)Z",
2053        (void*) android_content_AssetManager_applyStyle },
2054    { "retrieveAttributes","(J[I[I[I)Z",
2055        (void*) android_content_AssetManager_retrieveAttributes },
2056    { "getArraySize","(I)I",
2057        (void*) android_content_AssetManager_getArraySize },
2058    { "retrieveArray","(I[I)I",
2059        (void*) android_content_AssetManager_retrieveArray },
2060
2061    // XML files.
2062    { "openXmlAssetNative", "(ILjava/lang/String;)J",
2063        (void*) android_content_AssetManager_openXmlAssetNative },
2064
2065    // Arrays.
2066    { "getArrayStringResource","(I)[Ljava/lang/String;",
2067        (void*) android_content_AssetManager_getArrayStringResource },
2068    { "getArrayStringInfo","(I)[I",
2069        (void*) android_content_AssetManager_getArrayStringInfo },
2070    { "getArrayIntResource","(I)[I",
2071        (void*) android_content_AssetManager_getArrayIntResource },
2072    { "getStyleAttributes","(I)[I",
2073        (void*) android_content_AssetManager_getStyleAttributes },
2074
2075    // Bookkeeping.
2076    { "init",           "(Z)V",
2077        (void*) android_content_AssetManager_init },
2078    { "destroy",        "()V",
2079        (void*) android_content_AssetManager_destroy },
2080    { "getGlobalAssetCount", "()I",
2081        (void*) android_content_AssetManager_getGlobalAssetCount },
2082    { "getAssetAllocations", "()Ljava/lang/String;",
2083        (void*) android_content_AssetManager_getAssetAllocations },
2084    { "getGlobalAssetManagerCount", "()I",
2085        (void*) android_content_AssetManager_getGlobalAssetCount },
2086};
2087
2088int register_android_content_AssetManager(JNIEnv* env)
2089{
2090    jclass typedValue = env->FindClass("android/util/TypedValue");
2091    LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
2092    gTypedValueOffsets.mType
2093        = env->GetFieldID(typedValue, "type", "I");
2094    LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
2095    gTypedValueOffsets.mData
2096        = env->GetFieldID(typedValue, "data", "I");
2097    LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
2098    gTypedValueOffsets.mString
2099        = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
2100    LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
2101    gTypedValueOffsets.mAssetCookie
2102        = env->GetFieldID(typedValue, "assetCookie", "I");
2103    LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
2104    gTypedValueOffsets.mResourceId
2105        = env->GetFieldID(typedValue, "resourceId", "I");
2106    LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
2107    gTypedValueOffsets.mChangingConfigurations
2108        = env->GetFieldID(typedValue, "changingConfigurations", "I");
2109    LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
2110    gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
2111    LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
2112
2113    jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
2114    LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
2115    gAssetFileDescriptorOffsets.mFd
2116        = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
2117    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
2118    gAssetFileDescriptorOffsets.mStartOffset
2119        = env->GetFieldID(assetFd, "mStartOffset", "J");
2120    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
2121    gAssetFileDescriptorOffsets.mLength
2122        = env->GetFieldID(assetFd, "mLength", "J");
2123    LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
2124
2125    jclass assetManager = env->FindClass("android/content/res/AssetManager");
2126    LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
2127    gAssetManagerOffsets.mObject
2128        = env->GetFieldID(assetManager, "mObject", "J");
2129    LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
2130
2131    jclass stringClass = env->FindClass("java/lang/String");
2132    LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
2133    g_stringClass = (jclass)env->NewGlobalRef(stringClass);
2134    LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
2135
2136    jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
2137    LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
2138    gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
2139    gSparseArrayOffsets.constructor =
2140            env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
2141    LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
2142    gSparseArrayOffsets.put =
2143            env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
2144    LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
2145
2146    return AndroidRuntime::registerNativeMethods(env,
2147            "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
2148}
2149
2150}; // namespace android
2151