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