android_util_AssetManager.cpp revision 3a091b79978caa9b5d58ae19f693279e5a717c2a
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    config.mcc = (uint16_t)mcc;
619    config.mnc = (uint16_t)mnc;
620    config.orientation = (uint8_t)orientation;
621    config.touchscreen = (uint8_t)touchscreen;
622    config.density = (uint16_t)density;
623    config.keyboard = (uint8_t)keyboard;
624    config.inputFlags = (uint8_t)keyboardHidden;
625    config.navigation = (uint8_t)navigation;
626    config.screenWidth = (uint16_t)screenWidth;
627    config.screenHeight = (uint16_t)screenHeight;
628    config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
629    config.screenWidthDp = (uint16_t)screenWidthDp;
630    config.screenHeightDp = (uint16_t)screenHeightDp;
631    config.screenLayout = (uint8_t)screenLayout;
632    config.uiMode = (uint8_t)uiMode;
633    config.sdkVersion = (uint16_t)sdkVersion;
634    config.minorVersion = 0;
635    am->setConfiguration(config, locale8);
636
637    if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
638}
639
640static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
641                                                            jstring name,
642                                                            jstring defType,
643                                                            jstring defPackage)
644{
645    ScopedStringChars name16(env, name);
646    if (name16.get() == NULL) {
647        return 0;
648    }
649
650    AssetManager* am = assetManagerForJavaObject(env, clazz);
651    if (am == NULL) {
652        return 0;
653    }
654
655    const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
656        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
657        : NULL;
658    jsize defTypeLen = defType
659        ? env->GetStringLength(defType) : 0;
660    const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
661        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
662                                                                NULL))
663        : NULL;
664    jsize defPackageLen = defPackage
665        ? env->GetStringLength(defPackage) : 0;
666
667    jint ident = am->getResources().identifierForName(
668        reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
669        defType16, defTypeLen, defPackage16, defPackageLen);
670
671    if (defPackage16) {
672        env->ReleaseStringChars(defPackage,
673                                reinterpret_cast<const jchar*>(defPackage16));
674    }
675    if (defType16) {
676        env->ReleaseStringChars(defType,
677                                reinterpret_cast<const jchar*>(defType16));
678    }
679
680    return ident;
681}
682
683static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
684                                                            jint resid)
685{
686    AssetManager* am = assetManagerForJavaObject(env, clazz);
687    if (am == NULL) {
688        return NULL;
689    }
690
691    ResTable::resource_name name;
692    if (!am->getResources().getResourceName(resid, true, &name)) {
693        return NULL;
694    }
695
696    String16 str;
697    if (name.package != NULL) {
698        str.setTo(name.package, name.packageLen);
699    }
700    if (name.type8 != NULL || name.type != NULL) {
701        if (str.size() > 0) {
702            char16_t div = ':';
703            str.append(&div, 1);
704        }
705        if (name.type8 != NULL) {
706            str.append(String16(name.type8, name.typeLen));
707        } else {
708            str.append(name.type, name.typeLen);
709        }
710    }
711    if (name.name8 != NULL || name.name != NULL) {
712        if (str.size() > 0) {
713            char16_t div = '/';
714            str.append(&div, 1);
715        }
716        if (name.name8 != NULL) {
717            str.append(String16(name.name8, name.nameLen));
718        } else {
719            str.append(name.name, name.nameLen);
720        }
721    }
722
723    return env->NewString((const jchar*)str.string(), str.size());
724}
725
726static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
727                                                                   jint resid)
728{
729    AssetManager* am = assetManagerForJavaObject(env, clazz);
730    if (am == NULL) {
731        return NULL;
732    }
733
734    ResTable::resource_name name;
735    if (!am->getResources().getResourceName(resid, true, &name)) {
736        return NULL;
737    }
738
739    if (name.package != NULL) {
740        return env->NewString((const jchar*)name.package, name.packageLen);
741    }
742
743    return NULL;
744}
745
746static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
747                                                                jint resid)
748{
749    AssetManager* am = assetManagerForJavaObject(env, clazz);
750    if (am == NULL) {
751        return NULL;
752    }
753
754    ResTable::resource_name name;
755    if (!am->getResources().getResourceName(resid, true, &name)) {
756        return NULL;
757    }
758
759    if (name.type8 != NULL) {
760        return env->NewStringUTF(name.type8);
761    }
762
763    if (name.type != NULL) {
764        return env->NewString((const jchar*)name.type, name.typeLen);
765    }
766
767    return NULL;
768}
769
770static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
771                                                                 jint resid)
772{
773    AssetManager* am = assetManagerForJavaObject(env, clazz);
774    if (am == NULL) {
775        return NULL;
776    }
777
778    ResTable::resource_name name;
779    if (!am->getResources().getResourceName(resid, true, &name)) {
780        return NULL;
781    }
782
783    if (name.name8 != NULL) {
784        return env->NewStringUTF(name.name8);
785    }
786
787    if (name.name != NULL) {
788        return env->NewString((const jchar*)name.name, name.nameLen);
789    }
790
791    return NULL;
792}
793
794static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
795                                                           jint ident,
796                                                           jshort density,
797                                                           jobject outValue,
798                                                           jboolean resolve)
799{
800    if (outValue == NULL) {
801         jniThrowNullPointerException(env, "outValue");
802         return 0;
803    }
804    AssetManager* am = assetManagerForJavaObject(env, clazz);
805    if (am == NULL) {
806        return 0;
807    }
808    const ResTable& res(am->getResources());
809
810    Res_value value;
811    ResTable_config config;
812    uint32_t typeSpecFlags;
813    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
814    if (kThrowOnBadId) {
815        if (block == BAD_INDEX) {
816            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
817            return 0;
818        }
819    }
820    uint32_t ref = ident;
821    if (resolve) {
822        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
823        if (kThrowOnBadId) {
824            if (block == BAD_INDEX) {
825                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
826                return 0;
827            }
828        }
829    }
830    if (block >= 0) {
831        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
832    }
833
834    return static_cast<jint>(block);
835}
836
837static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
838                                                           jint ident, jint bagEntryId,
839                                                           jobject outValue, jboolean resolve)
840{
841    AssetManager* am = assetManagerForJavaObject(env, clazz);
842    if (am == NULL) {
843        return 0;
844    }
845    const ResTable& res(am->getResources());
846
847    // Now lock down the resource object and start pulling stuff from it.
848    res.lock();
849
850    ssize_t block = -1;
851    Res_value value;
852
853    const ResTable::bag_entry* entry = NULL;
854    uint32_t typeSpecFlags;
855    ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
856
857    for (ssize_t i=0; i<entryCount; i++) {
858        if (((uint32_t)bagEntryId) == entry->map.name.ident) {
859            block = entry->stringBlock;
860            value = entry->map.value;
861        }
862        entry++;
863    }
864
865    res.unlock();
866
867    if (block < 0) {
868        return static_cast<jint>(block);
869    }
870
871    uint32_t ref = ident;
872    if (resolve) {
873        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
874        if (kThrowOnBadId) {
875            if (block == BAD_INDEX) {
876                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
877                return 0;
878            }
879        }
880    }
881    if (block >= 0) {
882        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
883    }
884
885    return static_cast<jint>(block);
886}
887
888static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
889{
890    AssetManager* am = assetManagerForJavaObject(env, clazz);
891    if (am == NULL) {
892        return 0;
893    }
894    return am->getResources().getTableCount();
895}
896
897static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
898                                                           jint block)
899{
900    AssetManager* am = assetManagerForJavaObject(env, clazz);
901    if (am == NULL) {
902        return 0;
903    }
904    return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
905}
906
907static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
908                                                       jint cookie)
909{
910    AssetManager* am = assetManagerForJavaObject(env, clazz);
911    if (am == NULL) {
912        return NULL;
913    }
914    String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
915    if (name.length() == 0) {
916        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
917        return NULL;
918    }
919    jstring str = env->NewStringUTF(name.string());
920    return str;
921}
922
923static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
924{
925    AssetManager* am = assetManagerForJavaObject(env, clazz);
926    if (am == NULL) {
927        return 0;
928    }
929
930    const ResTable& res = am->getResources();
931
932    jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
933            gSparseArrayOffsets.constructor);
934    const size_t N = res.getBasePackageCount();
935    for (size_t i = 0; i < N; i++) {
936        const String16 name = res.getBasePackageName(i);
937        env->CallVoidMethod(
938            sparseArray, gSparseArrayOffsets.put,
939            static_cast<jint>(res.getBasePackageId(i)),
940            env->NewString(reinterpret_cast<const jchar*>(name.string()),
941                           name.size()));
942    }
943    return sparseArray;
944}
945
946static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
947{
948    AssetManager* am = assetManagerForJavaObject(env, clazz);
949    if (am == NULL) {
950        return 0;
951    }
952    return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
953}
954
955static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
956                                                     jlong themeHandle)
957{
958    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
959    delete theme;
960}
961
962static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
963                                                         jlong themeHandle,
964                                                         jint styleRes,
965                                                         jboolean force)
966{
967    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
968    theme->applyStyle(styleRes, force ? true : false);
969}
970
971static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
972                                                   jlong destHandle, jlong srcHandle)
973{
974    ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
975    ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
976    dest->setTo(*src);
977}
978
979static jint android_content_AssetManager_loadThemeAttributeValue(
980    JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
981{
982    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
983    const ResTable& res(theme->getResTable());
984
985    Res_value value;
986    // XXX value could be different in different configs!
987    uint32_t typeSpecFlags = 0;
988    ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
989    uint32_t ref = 0;
990    if (resolve) {
991        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
992        if (kThrowOnBadId) {
993            if (block == BAD_INDEX) {
994                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
995                return 0;
996            }
997        }
998    }
999    return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
1000}
1001
1002static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
1003                                                   jlong themeHandle, jint pri,
1004                                                   jstring tag, jstring prefix)
1005{
1006    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
1007    const ResTable& res(theme->getResTable());
1008    (void)res;
1009
1010    // XXX Need to use params.
1011    theme->dumpToLog();
1012}
1013
1014class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1015public:
1016    XmlAttributeFinder(const ResXMLParser* parser)
1017        : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1018        , mParser(parser) {}
1019
1020    inline uint32_t getAttribute(jsize index) const {
1021        return mParser->getAttributeNameResID(index);
1022    }
1023
1024private:
1025    const ResXMLParser* mParser;
1026};
1027
1028class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1029public:
1030    BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1031        : BackTrackingAttributeFinder(start, end) {}
1032
1033    inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1034        return entry->map.name.ident;
1035    }
1036};
1037
1038static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1039                                                          jlong themeToken,
1040                                                          jint defStyleAttr,
1041                                                          jint defStyleRes,
1042                                                          jintArray inValues,
1043                                                          jintArray attrs,
1044                                                          jintArray outValues,
1045                                                          jintArray outIndices)
1046{
1047    if (themeToken == 0) {
1048        jniThrowNullPointerException(env, "theme token");
1049        return JNI_FALSE;
1050    }
1051    if (attrs == NULL) {
1052        jniThrowNullPointerException(env, "attrs");
1053        return JNI_FALSE;
1054    }
1055    if (outValues == NULL) {
1056        jniThrowNullPointerException(env, "out values");
1057        return JNI_FALSE;
1058    }
1059
1060    if (kDebugStyles) {
1061        ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
1062              "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
1063    }
1064
1065    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1066    const ResTable& res = theme->getResTable();
1067    ResTable_config config;
1068    Res_value value;
1069
1070    const jsize NI = env->GetArrayLength(attrs);
1071    const jsize NV = env->GetArrayLength(outValues);
1072    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1073        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1074        return JNI_FALSE;
1075    }
1076
1077    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1078    if (src == NULL) {
1079        return JNI_FALSE;
1080    }
1081
1082    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1083    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1084
1085    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1086    jint* dest = baseDest;
1087    if (dest == NULL) {
1088        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1089        return JNI_FALSE;
1090    }
1091
1092    jint* indices = NULL;
1093    int indicesIdx = 0;
1094    if (outIndices != NULL) {
1095        if (env->GetArrayLength(outIndices) > NI) {
1096            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1097        }
1098    }
1099
1100    // Load default style from attribute, if specified...
1101    uint32_t defStyleBagTypeSetFlags = 0;
1102    if (defStyleAttr != 0) {
1103        Res_value value;
1104        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1105            if (value.dataType == Res_value::TYPE_REFERENCE) {
1106                defStyleRes = value.data;
1107            }
1108        }
1109    }
1110
1111    // Now lock down the resource object and start pulling stuff from it.
1112    res.lock();
1113
1114    // Retrieve the default style bag, if requested.
1115    const ResTable::bag_entry* defStyleStart = NULL;
1116    uint32_t defStyleTypeSetFlags = 0;
1117    ssize_t bagOff = defStyleRes != 0
1118            ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1119    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1120    const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1121    BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1122
1123    // Now iterate through all of the attributes that the client has requested,
1124    // filling in each with whatever data we can find.
1125    ssize_t block = 0;
1126    uint32_t typeSetFlags;
1127    for (jsize ii=0; ii<NI; ii++) {
1128        const uint32_t curIdent = (uint32_t)src[ii];
1129
1130        if (kDebugStyles) {
1131            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1132        }
1133
1134        // Try to find a value for this attribute...  we prioritize values
1135        // coming from, first XML attributes, then XML style, then default
1136        // style, and finally the theme.
1137        value.dataType = Res_value::TYPE_NULL;
1138        value.data = Res_value::DATA_NULL_UNDEFINED;
1139        typeSetFlags = 0;
1140        config.density = 0;
1141
1142        // Retrieve the current input value if available.
1143        if (NSV > 0 && srcValues[ii] != 0) {
1144            block = -1;
1145            value.dataType = Res_value::TYPE_ATTRIBUTE;
1146            value.data = srcValues[ii];
1147            if (kDebugStyles) {
1148                ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1149            }
1150        }
1151
1152        if (value.dataType == Res_value::TYPE_NULL) {
1153            const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1154            if (defStyleEntry != defStyleEnd) {
1155                block = defStyleEntry->stringBlock;
1156                typeSetFlags = defStyleTypeSetFlags;
1157                value = defStyleEntry->map.value;
1158                if (kDebugStyles) {
1159                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1160                }
1161            }
1162        }
1163
1164        uint32_t resid = 0;
1165        if (value.dataType != Res_value::TYPE_NULL) {
1166            // Take care of resolving the found resource to its final value.
1167            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1168                    &resid, &typeSetFlags, &config);
1169            if (newBlock >= 0) block = newBlock;
1170            if (kDebugStyles) {
1171                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1172            }
1173        } else {
1174            // If we still don't have a value for this attribute, try to find
1175            // it in the theme!
1176            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1177            if (newBlock >= 0) {
1178                if (kDebugStyles) {
1179                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1180                }
1181                newBlock = res.resolveReference(&value, block, &resid,
1182                        &typeSetFlags, &config);
1183                if (kThrowOnBadId) {
1184                    if (newBlock == BAD_INDEX) {
1185                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1186                        return JNI_FALSE;
1187                    }
1188                }
1189                if (newBlock >= 0) block = newBlock;
1190                if (kDebugStyles) {
1191                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1192                }
1193            }
1194        }
1195
1196        // Deal with the special @null value -- it turns back to TYPE_NULL.
1197        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1198            if (kDebugStyles) {
1199                ALOGI("-> Setting to @null!");
1200            }
1201            value.dataType = Res_value::TYPE_NULL;
1202            value.data = Res_value::DATA_NULL_UNDEFINED;
1203            block = -1;
1204        }
1205
1206        if (kDebugStyles) {
1207            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1208                  value.data);
1209        }
1210
1211        // Write the final value back to Java.
1212        dest[STYLE_TYPE] = value.dataType;
1213        dest[STYLE_DATA] = value.data;
1214        dest[STYLE_ASSET_COOKIE] =
1215            block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1216        dest[STYLE_RESOURCE_ID] = resid;
1217        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1218        dest[STYLE_DENSITY] = config.density;
1219
1220        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1221            indicesIdx++;
1222            indices[indicesIdx] = ii;
1223        }
1224
1225        dest += STYLE_NUM_ENTRIES;
1226    }
1227
1228    res.unlock();
1229
1230    if (indices != NULL) {
1231        indices[0] = indicesIdx;
1232        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1233    }
1234    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1235    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1236    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1237
1238    return JNI_TRUE;
1239}
1240
1241static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1242                                                        jlong themeToken,
1243                                                        jint defStyleAttr,
1244                                                        jint defStyleRes,
1245                                                        jlong xmlParserToken,
1246                                                        jintArray attrs,
1247                                                        jintArray outValues,
1248                                                        jintArray outIndices)
1249{
1250    if (themeToken == 0) {
1251        jniThrowNullPointerException(env, "theme token");
1252        return JNI_FALSE;
1253    }
1254    if (attrs == NULL) {
1255        jniThrowNullPointerException(env, "attrs");
1256        return JNI_FALSE;
1257    }
1258    if (outValues == NULL) {
1259        jniThrowNullPointerException(env, "out values");
1260        return JNI_FALSE;
1261    }
1262
1263    if (kDebugStyles) {
1264    ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
1265          "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
1266          xmlParserToken);
1267    }
1268
1269    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1270    const ResTable& res = theme->getResTable();
1271    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1272    ResTable_config config;
1273    Res_value value;
1274
1275    const jsize NI = env->GetArrayLength(attrs);
1276    const jsize NV = env->GetArrayLength(outValues);
1277    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1278        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1279        return JNI_FALSE;
1280    }
1281
1282    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1283    if (src == NULL) {
1284        return JNI_FALSE;
1285    }
1286
1287    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1288    jint* dest = baseDest;
1289    if (dest == NULL) {
1290        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1291        return JNI_FALSE;
1292    }
1293
1294    jint* indices = NULL;
1295    int indicesIdx = 0;
1296    if (outIndices != NULL) {
1297        if (env->GetArrayLength(outIndices) > NI) {
1298            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1299        }
1300    }
1301
1302    // Load default style from attribute, if specified...
1303    uint32_t defStyleBagTypeSetFlags = 0;
1304    if (defStyleAttr != 0) {
1305        Res_value value;
1306        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1307            if (value.dataType == Res_value::TYPE_REFERENCE) {
1308                defStyleRes = value.data;
1309            }
1310        }
1311    }
1312
1313    // Retrieve the style class associated with the current XML tag.
1314    int style = 0;
1315    uint32_t styleBagTypeSetFlags = 0;
1316    if (xmlParser != NULL) {
1317        ssize_t idx = xmlParser->indexOfStyle();
1318        if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1319            if (value.dataType == value.TYPE_ATTRIBUTE) {
1320                if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1321                    value.dataType = Res_value::TYPE_NULL;
1322                }
1323            }
1324            if (value.dataType == value.TYPE_REFERENCE) {
1325                style = value.data;
1326            }
1327        }
1328    }
1329
1330    // Now lock down the resource object and start pulling stuff from it.
1331    res.lock();
1332
1333    // Retrieve the default style bag, if requested.
1334    const ResTable::bag_entry* defStyleAttrStart = NULL;
1335    uint32_t defStyleTypeSetFlags = 0;
1336    ssize_t bagOff = defStyleRes != 0
1337            ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1338    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1339    const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1340    BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1341
1342    // Retrieve the style class bag, if requested.
1343    const ResTable::bag_entry* styleAttrStart = NULL;
1344    uint32_t styleTypeSetFlags = 0;
1345    bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1346    styleTypeSetFlags |= styleBagTypeSetFlags;
1347    const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1348    BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1349
1350    // Retrieve the XML attributes, if requested.
1351    static const ssize_t kXmlBlock = 0x10000000;
1352    XmlAttributeFinder xmlAttrFinder(xmlParser);
1353    const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1354
1355    // Now iterate through all of the attributes that the client has requested,
1356    // filling in each with whatever data we can find.
1357    ssize_t block = 0;
1358    uint32_t typeSetFlags;
1359    for (jsize ii = 0; ii < NI; ii++) {
1360        const uint32_t curIdent = (uint32_t)src[ii];
1361
1362        if (kDebugStyles) {
1363            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1364        }
1365
1366        // Try to find a value for this attribute...  we prioritize values
1367        // coming from, first XML attributes, then XML style, then default
1368        // style, and finally the theme.
1369        value.dataType = Res_value::TYPE_NULL;
1370        value.data = Res_value::DATA_NULL_UNDEFINED;
1371        typeSetFlags = 0;
1372        config.density = 0;
1373
1374        // Walk through the xml attributes looking for the requested attribute.
1375        const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1376        if (xmlAttrIdx != xmlAttrEnd) {
1377            // We found the attribute we were looking for.
1378            block = kXmlBlock;
1379            xmlParser->getAttributeValue(xmlAttrIdx, &value);
1380            if (kDebugStyles) {
1381                ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1382            }
1383        }
1384
1385        if (value.dataType == Res_value::TYPE_NULL) {
1386            // Walk through the style class values looking for the requested attribute.
1387            const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1388            if (styleAttrEntry != styleAttrEnd) {
1389                // We found the attribute we were looking for.
1390                block = styleAttrEntry->stringBlock;
1391                typeSetFlags = styleTypeSetFlags;
1392                value = styleAttrEntry->map.value;
1393                if (kDebugStyles) {
1394                    ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1395                }
1396            }
1397        }
1398
1399        if (value.dataType == Res_value::TYPE_NULL) {
1400            // Walk through the default style values looking for the requested attribute.
1401            const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1402            if (defStyleAttrEntry != defStyleAttrEnd) {
1403                // We found the attribute we were looking for.
1404                block = defStyleAttrEntry->stringBlock;
1405                typeSetFlags = styleTypeSetFlags;
1406                value = defStyleAttrEntry->map.value;
1407                if (kDebugStyles) {
1408                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1409                }
1410            }
1411        }
1412
1413        uint32_t resid = 0;
1414        if (value.dataType != Res_value::TYPE_NULL) {
1415            // Take care of resolving the found resource to its final value.
1416            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1417                    &resid, &typeSetFlags, &config);
1418            if (newBlock >= 0) {
1419                block = newBlock;
1420            }
1421
1422            if (kDebugStyles) {
1423                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1424            }
1425        } else {
1426            // If we still don't have a value for this attribute, try to find
1427            // it in the theme!
1428            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1429            if (newBlock >= 0) {
1430                if (kDebugStyles) {
1431                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1432                }
1433                newBlock = res.resolveReference(&value, block, &resid,
1434                        &typeSetFlags, &config);
1435                if (kThrowOnBadId) {
1436                    if (newBlock == BAD_INDEX) {
1437                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1438                        return JNI_FALSE;
1439                    }
1440                }
1441
1442                if (newBlock >= 0) {
1443                    block = newBlock;
1444                }
1445
1446                if (kDebugStyles) {
1447                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1448                }
1449            }
1450        }
1451
1452        // Deal with the special @null value -- it turns back to TYPE_NULL.
1453        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1454            if (kDebugStyles) {
1455                ALOGI("-> Setting to @null!");
1456            }
1457            value.dataType = Res_value::TYPE_NULL;
1458            value.data = Res_value::DATA_NULL_UNDEFINED;
1459            block = kXmlBlock;
1460        }
1461
1462        if (kDebugStyles) {
1463            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1464        }
1465
1466        // Write the final value back to Java.
1467        dest[STYLE_TYPE] = value.dataType;
1468        dest[STYLE_DATA] = value.data;
1469        dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1470            static_cast<jint>(res.getTableCookie(block)) : -1;
1471        dest[STYLE_RESOURCE_ID] = resid;
1472        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1473        dest[STYLE_DENSITY] = config.density;
1474
1475        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1476            indicesIdx++;
1477            indices[indicesIdx] = ii;
1478        }
1479
1480        dest += STYLE_NUM_ENTRIES;
1481    }
1482
1483    res.unlock();
1484
1485    if (indices != NULL) {
1486        indices[0] = indicesIdx;
1487        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1488    }
1489    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1490    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1491
1492    return JNI_TRUE;
1493}
1494
1495static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1496                                                        jlong xmlParserToken,
1497                                                        jintArray attrs,
1498                                                        jintArray outValues,
1499                                                        jintArray outIndices)
1500{
1501    if (xmlParserToken == 0) {
1502        jniThrowNullPointerException(env, "xmlParserToken");
1503        return JNI_FALSE;
1504    }
1505    if (attrs == NULL) {
1506        jniThrowNullPointerException(env, "attrs");
1507        return JNI_FALSE;
1508    }
1509    if (outValues == NULL) {
1510        jniThrowNullPointerException(env, "out values");
1511        return JNI_FALSE;
1512    }
1513
1514    AssetManager* am = assetManagerForJavaObject(env, clazz);
1515    if (am == NULL) {
1516        return JNI_FALSE;
1517    }
1518    const ResTable& res(am->getResources());
1519    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1520    ResTable_config config;
1521    Res_value value;
1522
1523    const jsize NI = env->GetArrayLength(attrs);
1524    const jsize NV = env->GetArrayLength(outValues);
1525    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1526        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1527        return JNI_FALSE;
1528    }
1529
1530    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1531    if (src == NULL) {
1532        return JNI_FALSE;
1533    }
1534
1535    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1536    jint* dest = baseDest;
1537    if (dest == NULL) {
1538        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1539        return JNI_FALSE;
1540    }
1541
1542    jint* indices = NULL;
1543    int indicesIdx = 0;
1544    if (outIndices != NULL) {
1545        if (env->GetArrayLength(outIndices) > NI) {
1546            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1547        }
1548    }
1549
1550    // Now lock down the resource object and start pulling stuff from it.
1551    res.lock();
1552
1553    // Retrieve the XML attributes, if requested.
1554    const jsize NX = xmlParser->getAttributeCount();
1555    jsize ix=0;
1556    uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1557
1558    static const ssize_t kXmlBlock = 0x10000000;
1559
1560    // Now iterate through all of the attributes that the client has requested,
1561    // filling in each with whatever data we can find.
1562    ssize_t block = 0;
1563    uint32_t typeSetFlags;
1564    for (jsize ii=0; ii<NI; ii++) {
1565        const uint32_t curIdent = (uint32_t)src[ii];
1566
1567        // Try to find a value for this attribute...
1568        value.dataType = Res_value::TYPE_NULL;
1569        value.data = Res_value::DATA_NULL_UNDEFINED;
1570        typeSetFlags = 0;
1571        config.density = 0;
1572
1573        // Skip through XML attributes until the end or the next possible match.
1574        while (ix < NX && curIdent > curXmlAttr) {
1575            ix++;
1576            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1577        }
1578        // Retrieve the current XML attribute if it matches, and step to next.
1579        if (ix < NX && curIdent == curXmlAttr) {
1580            block = kXmlBlock;
1581            xmlParser->getAttributeValue(ix, &value);
1582            ix++;
1583            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1584        }
1585
1586        //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1587        uint32_t resid = 0;
1588        if (value.dataType != Res_value::TYPE_NULL) {
1589            // Take care of resolving the found resource to its final value.
1590            //printf("Resolving attribute reference\n");
1591            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1592                    &typeSetFlags, &config);
1593            if (kThrowOnBadId) {
1594                if (newBlock == BAD_INDEX) {
1595                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1596                    return JNI_FALSE;
1597                }
1598            }
1599            if (newBlock >= 0) block = newBlock;
1600        }
1601
1602        // Deal with the special @null value -- it turns back to TYPE_NULL.
1603        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1604            value.dataType = Res_value::TYPE_NULL;
1605            value.data = Res_value::DATA_NULL_UNDEFINED;
1606        }
1607
1608        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1609
1610        // Write the final value back to Java.
1611        dest[STYLE_TYPE] = value.dataType;
1612        dest[STYLE_DATA] = value.data;
1613        dest[STYLE_ASSET_COOKIE] =
1614            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1615        dest[STYLE_RESOURCE_ID] = resid;
1616        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1617        dest[STYLE_DENSITY] = config.density;
1618
1619        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1620            indicesIdx++;
1621            indices[indicesIdx] = ii;
1622        }
1623
1624        dest += STYLE_NUM_ENTRIES;
1625    }
1626
1627    res.unlock();
1628
1629    if (indices != NULL) {
1630        indices[0] = indicesIdx;
1631        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1632    }
1633
1634    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1635    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1636
1637    return JNI_TRUE;
1638}
1639
1640static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1641                                                       jint id)
1642{
1643    AssetManager* am = assetManagerForJavaObject(env, clazz);
1644    if (am == NULL) {
1645        return 0;
1646    }
1647    const ResTable& res(am->getResources());
1648
1649    res.lock();
1650    const ResTable::bag_entry* defStyleEnt = NULL;
1651    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1652    res.unlock();
1653
1654    return static_cast<jint>(bagOff);
1655}
1656
1657static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1658                                                        jint id,
1659                                                        jintArray outValues)
1660{
1661    if (outValues == NULL) {
1662        jniThrowNullPointerException(env, "out values");
1663        return JNI_FALSE;
1664    }
1665
1666    AssetManager* am = assetManagerForJavaObject(env, clazz);
1667    if (am == NULL) {
1668        return JNI_FALSE;
1669    }
1670    const ResTable& res(am->getResources());
1671    ResTable_config config;
1672    Res_value value;
1673    ssize_t block;
1674
1675    const jsize NV = env->GetArrayLength(outValues);
1676
1677    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1678    jint* dest = baseDest;
1679    if (dest == NULL) {
1680        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1681        return JNI_FALSE;
1682    }
1683
1684    // Now lock down the resource object and start pulling stuff from it.
1685    res.lock();
1686
1687    const ResTable::bag_entry* arrayEnt = NULL;
1688    uint32_t arrayTypeSetFlags = 0;
1689    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1690    const ResTable::bag_entry* endArrayEnt = arrayEnt +
1691        (bagOff >= 0 ? bagOff : 0);
1692
1693    int i = 0;
1694    uint32_t typeSetFlags;
1695    while (i < NV && arrayEnt < endArrayEnt) {
1696        block = arrayEnt->stringBlock;
1697        typeSetFlags = arrayTypeSetFlags;
1698        config.density = 0;
1699        value = arrayEnt->map.value;
1700
1701        uint32_t resid = 0;
1702        if (value.dataType != Res_value::TYPE_NULL) {
1703            // Take care of resolving the found resource to its final value.
1704            //printf("Resolving attribute reference\n");
1705            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1706                    &typeSetFlags, &config);
1707            if (kThrowOnBadId) {
1708                if (newBlock == BAD_INDEX) {
1709                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1710                    return JNI_FALSE;
1711                }
1712            }
1713            if (newBlock >= 0) block = newBlock;
1714        }
1715
1716        // Deal with the special @null value -- it turns back to TYPE_NULL.
1717        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1718            value.dataType = Res_value::TYPE_NULL;
1719            value.data = Res_value::DATA_NULL_UNDEFINED;
1720        }
1721
1722        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1723
1724        // Write the final value back to Java.
1725        dest[STYLE_TYPE] = value.dataType;
1726        dest[STYLE_DATA] = value.data;
1727        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1728        dest[STYLE_RESOURCE_ID] = resid;
1729        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1730        dest[STYLE_DENSITY] = config.density;
1731        dest += STYLE_NUM_ENTRIES;
1732        i+= STYLE_NUM_ENTRIES;
1733        arrayEnt++;
1734    }
1735
1736    i /= STYLE_NUM_ENTRIES;
1737
1738    res.unlock();
1739
1740    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1741
1742    return i;
1743}
1744
1745static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1746                                                         jint cookie,
1747                                                         jstring fileName)
1748{
1749    AssetManager* am = assetManagerForJavaObject(env, clazz);
1750    if (am == NULL) {
1751        return 0;
1752    }
1753
1754    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1755
1756    ScopedUtfChars fileName8(env, fileName);
1757    if (fileName8.c_str() == NULL) {
1758        return 0;
1759    }
1760
1761    int32_t assetCookie = static_cast<int32_t>(cookie);
1762    Asset* a = assetCookie
1763        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1764        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1765
1766    if (a == NULL) {
1767        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1768        return 0;
1769    }
1770
1771    const DynamicRefTable* dynamicRefTable =
1772            am->getResources().getDynamicRefTableForCookie(assetCookie);
1773    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1774    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1775    a->close();
1776    delete a;
1777
1778    if (err != NO_ERROR) {
1779        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1780        return 0;
1781    }
1782
1783    return reinterpret_cast<jlong>(block);
1784}
1785
1786static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1787                                                                 jint arrayResId)
1788{
1789    AssetManager* am = assetManagerForJavaObject(env, clazz);
1790    if (am == NULL) {
1791        return NULL;
1792    }
1793    const ResTable& res(am->getResources());
1794
1795    const ResTable::bag_entry* startOfBag;
1796    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1797    if (N < 0) {
1798        return NULL;
1799    }
1800
1801    jintArray array = env->NewIntArray(N * 2);
1802    if (array == NULL) {
1803        res.unlockBag(startOfBag);
1804        return NULL;
1805    }
1806
1807    Res_value value;
1808    const ResTable::bag_entry* bag = startOfBag;
1809    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1810        jint stringIndex = -1;
1811        jint stringBlock = 0;
1812        value = bag->map.value;
1813
1814        // Take care of resolving the found resource to its final value.
1815        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1816        if (value.dataType == Res_value::TYPE_STRING) {
1817            stringIndex = value.data;
1818        }
1819
1820        if (kThrowOnBadId) {
1821            if (stringBlock == BAD_INDEX) {
1822                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1823                return array;
1824            }
1825        }
1826
1827        //todo: It might be faster to allocate a C array to contain
1828        //      the blocknums and indices, put them in there and then
1829        //      do just one SetIntArrayRegion()
1830        env->SetIntArrayRegion(array, j, 1, &stringBlock);
1831        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1832        j = j + 2;
1833    }
1834    res.unlockBag(startOfBag);
1835    return array;
1836}
1837
1838static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1839                                                                        jint arrayResId)
1840{
1841    AssetManager* am = assetManagerForJavaObject(env, clazz);
1842    if (am == NULL) {
1843        return NULL;
1844    }
1845    const ResTable& res(am->getResources());
1846
1847    const ResTable::bag_entry* startOfBag;
1848    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1849    if (N < 0) {
1850        return NULL;
1851    }
1852
1853    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1854    if (env->ExceptionCheck()) {
1855        res.unlockBag(startOfBag);
1856        return NULL;
1857    }
1858
1859    Res_value value;
1860    const ResTable::bag_entry* bag = startOfBag;
1861    size_t strLen = 0;
1862    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1863        value = bag->map.value;
1864        jstring str = NULL;
1865
1866        // Take care of resolving the found resource to its final value.
1867        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1868        if (kThrowOnBadId) {
1869            if (block == BAD_INDEX) {
1870                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1871                return array;
1872            }
1873        }
1874        if (value.dataType == Res_value::TYPE_STRING) {
1875            const ResStringPool* pool = res.getTableStringBlock(block);
1876            const char* str8 = pool->string8At(value.data, &strLen);
1877            if (str8 != NULL) {
1878                str = env->NewStringUTF(str8);
1879            } else {
1880                const char16_t* str16 = pool->stringAt(value.data, &strLen);
1881                str = env->NewString(reinterpret_cast<const jchar*>(str16),
1882                                     strLen);
1883            }
1884
1885            // If one of our NewString{UTF} calls failed due to memory, an
1886            // exception will be pending.
1887            if (env->ExceptionCheck()) {
1888                res.unlockBag(startOfBag);
1889                return NULL;
1890            }
1891
1892            env->SetObjectArrayElement(array, i, str);
1893
1894            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1895            // If we have a large amount of strings in our array, we might
1896            // overflow the local reference table of the VM.
1897            env->DeleteLocalRef(str);
1898        }
1899    }
1900    res.unlockBag(startOfBag);
1901    return array;
1902}
1903
1904static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1905                                                                        jint arrayResId)
1906{
1907    AssetManager* am = assetManagerForJavaObject(env, clazz);
1908    if (am == NULL) {
1909        return NULL;
1910    }
1911    const ResTable& res(am->getResources());
1912
1913    const ResTable::bag_entry* startOfBag;
1914    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1915    if (N < 0) {
1916        return NULL;
1917    }
1918
1919    jintArray array = env->NewIntArray(N);
1920    if (array == NULL) {
1921        res.unlockBag(startOfBag);
1922        return NULL;
1923    }
1924
1925    Res_value value;
1926    const ResTable::bag_entry* bag = startOfBag;
1927    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1928        value = bag->map.value;
1929
1930        // Take care of resolving the found resource to its final value.
1931        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1932        if (kThrowOnBadId) {
1933            if (block == BAD_INDEX) {
1934                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1935                return array;
1936            }
1937        }
1938        if (value.dataType >= Res_value::TYPE_FIRST_INT
1939                && value.dataType <= Res_value::TYPE_LAST_INT) {
1940            int intVal = value.data;
1941            env->SetIntArrayRegion(array, i, 1, &intVal);
1942        }
1943    }
1944    res.unlockBag(startOfBag);
1945    return array;
1946}
1947
1948static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1949                                                                 jint styleId)
1950{
1951    AssetManager* am = assetManagerForJavaObject(env, clazz);
1952    if (am == NULL) {
1953        return NULL;
1954    }
1955    const ResTable& res(am->getResources());
1956
1957    const ResTable::bag_entry* startOfBag;
1958    const ssize_t N = res.lockBag(styleId, &startOfBag);
1959    if (N < 0) {
1960        return NULL;
1961    }
1962
1963    jintArray array = env->NewIntArray(N);
1964    if (array == NULL) {
1965        res.unlockBag(startOfBag);
1966        return NULL;
1967    }
1968
1969    const ResTable::bag_entry* bag = startOfBag;
1970    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1971        int resourceId = bag->map.name.ident;
1972        env->SetIntArrayRegion(array, i, 1, &resourceId);
1973    }
1974    res.unlockBag(startOfBag);
1975    return array;
1976}
1977
1978static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1979{
1980    if (isSystem) {
1981        verifySystemIdmaps();
1982    }
1983    AssetManager* am = new AssetManager();
1984    if (am == NULL) {
1985        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1986        return;
1987    }
1988
1989    am->addDefaultAssets();
1990
1991    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1992    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1993}
1994
1995static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1996{
1997    AssetManager* am = (AssetManager*)
1998        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1999    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
2000    if (am != NULL) {
2001        delete am;
2002        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
2003    }
2004}
2005
2006static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2007{
2008    return Asset::getGlobalCount();
2009}
2010
2011static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
2012{
2013    String8 alloc = Asset::getAssetAllocations();
2014    if (alloc.length() <= 0) {
2015        return NULL;
2016    }
2017
2018    jstring str = env->NewStringUTF(alloc.string());
2019    return str;
2020}
2021
2022static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2023{
2024    return AssetManager::getGlobalCount();
2025}
2026
2027// ----------------------------------------------------------------------------
2028
2029/*
2030 * JNI registration.
2031 */
2032static JNINativeMethod gAssetManagerMethods[] = {
2033    /* name, signature, funcPtr */
2034
2035    // Basic asset stuff.
2036    { "openAsset",      "(Ljava/lang/String;I)J",
2037        (void*) android_content_AssetManager_openAsset },
2038    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2039        (void*) android_content_AssetManager_openAssetFd },
2040    { "openNonAssetNative", "(ILjava/lang/String;I)J",
2041        (void*) android_content_AssetManager_openNonAssetNative },
2042    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2043        (void*) android_content_AssetManager_openNonAssetFdNative },
2044    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
2045        (void*) android_content_AssetManager_list },
2046    { "destroyAsset",   "(J)V",
2047        (void*) android_content_AssetManager_destroyAsset },
2048    { "readAssetChar",  "(J)I",
2049        (void*) android_content_AssetManager_readAssetChar },
2050    { "readAsset",      "(J[BII)I",
2051        (void*) android_content_AssetManager_readAsset },
2052    { "seekAsset",      "(JJI)J",
2053        (void*) android_content_AssetManager_seekAsset },
2054    { "getAssetLength", "(J)J",
2055        (void*) android_content_AssetManager_getAssetLength },
2056    { "getAssetRemainingLength", "(J)J",
2057        (void*) android_content_AssetManager_getAssetRemainingLength },
2058    { "addAssetPathNative", "(Ljava/lang/String;)I",
2059        (void*) android_content_AssetManager_addAssetPath },
2060    { "addOverlayPath",   "(Ljava/lang/String;)I",
2061        (void*) android_content_AssetManager_addOverlayPath },
2062    { "isUpToDate",     "()Z",
2063        (void*) android_content_AssetManager_isUpToDate },
2064
2065    // Resources.
2066    { "setLocale",      "(Ljava/lang/String;)V",
2067        (void*) android_content_AssetManager_setLocale },
2068    { "getLocales",      "()[Ljava/lang/String;",
2069        (void*) android_content_AssetManager_getLocales },
2070    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2071        (void*) android_content_AssetManager_setConfiguration },
2072    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2073        (void*) android_content_AssetManager_getResourceIdentifier },
2074    { "getResourceName","(I)Ljava/lang/String;",
2075        (void*) android_content_AssetManager_getResourceName },
2076    { "getResourcePackageName","(I)Ljava/lang/String;",
2077        (void*) android_content_AssetManager_getResourcePackageName },
2078    { "getResourceTypeName","(I)Ljava/lang/String;",
2079        (void*) android_content_AssetManager_getResourceTypeName },
2080    { "getResourceEntryName","(I)Ljava/lang/String;",
2081        (void*) android_content_AssetManager_getResourceEntryName },
2082    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2083        (void*) android_content_AssetManager_loadResourceValue },
2084    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2085        (void*) android_content_AssetManager_loadResourceBagValue },
2086    { "getStringBlockCount","()I",
2087        (void*) android_content_AssetManager_getStringBlockCount },
2088    { "getNativeStringBlock","(I)J",
2089        (void*) android_content_AssetManager_getNativeStringBlock },
2090    { "getCookieName","(I)Ljava/lang/String;",
2091        (void*) android_content_AssetManager_getCookieName },
2092    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2093        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2094
2095    // Themes.
2096    { "newTheme", "()J",
2097        (void*) android_content_AssetManager_newTheme },
2098    { "deleteTheme", "(J)V",
2099        (void*) android_content_AssetManager_deleteTheme },
2100    { "applyThemeStyle", "(JIZ)V",
2101        (void*) android_content_AssetManager_applyThemeStyle },
2102    { "copyTheme", "(JJ)V",
2103        (void*) android_content_AssetManager_copyTheme },
2104    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2105        (void*) android_content_AssetManager_loadThemeAttributeValue },
2106    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2107        (void*) android_content_AssetManager_dumpTheme },
2108    { "applyStyle","(JIIJ[I[I[I)Z",
2109        (void*) android_content_AssetManager_applyStyle },
2110    { "resolveAttrs","(JII[I[I[I[I)Z",
2111        (void*) android_content_AssetManager_resolveAttrs },
2112    { "retrieveAttributes","(J[I[I[I)Z",
2113        (void*) android_content_AssetManager_retrieveAttributes },
2114    { "getArraySize","(I)I",
2115        (void*) android_content_AssetManager_getArraySize },
2116    { "retrieveArray","(I[I)I",
2117        (void*) android_content_AssetManager_retrieveArray },
2118
2119    // XML files.
2120    { "openXmlAssetNative", "(ILjava/lang/String;)J",
2121        (void*) android_content_AssetManager_openXmlAssetNative },
2122
2123    // Arrays.
2124    { "getArrayStringResource","(I)[Ljava/lang/String;",
2125        (void*) android_content_AssetManager_getArrayStringResource },
2126    { "getArrayStringInfo","(I)[I",
2127        (void*) android_content_AssetManager_getArrayStringInfo },
2128    { "getArrayIntResource","(I)[I",
2129        (void*) android_content_AssetManager_getArrayIntResource },
2130    { "getStyleAttributes","(I)[I",
2131        (void*) android_content_AssetManager_getStyleAttributes },
2132
2133    // Bookkeeping.
2134    { "init",           "(Z)V",
2135        (void*) android_content_AssetManager_init },
2136    { "destroy",        "()V",
2137        (void*) android_content_AssetManager_destroy },
2138    { "getGlobalAssetCount", "()I",
2139        (void*) android_content_AssetManager_getGlobalAssetCount },
2140    { "getAssetAllocations", "()Ljava/lang/String;",
2141        (void*) android_content_AssetManager_getAssetAllocations },
2142    { "getGlobalAssetManagerCount", "()I",
2143        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2144};
2145
2146int register_android_content_AssetManager(JNIEnv* env)
2147{
2148    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2149    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2150    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2151    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2152                                                 "Ljava/lang/CharSequence;");
2153    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2154    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2155    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2156                                                                 "changingConfigurations", "I");
2157    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
2158
2159    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2160    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2161                                                      "Landroid/os/ParcelFileDescriptor;");
2162    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2163    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
2164
2165    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2166    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
2167
2168    jclass stringClass = FindClassOrDie(env, "java/lang/String");
2169    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
2170
2171    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2172    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2173    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2174                                                       "<init>", "()V");
2175    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2176                                               "(ILjava/lang/Object;)V");
2177
2178    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2179                                NELEM(gAssetManagerMethods));
2180}
2181
2182}; // namespace android
2183