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