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