android_util_AssetManager.cpp revision 6698749dd4d4d6513b26aa9071af290b956b68a7
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 "jni.h"
23#include "JNIHelp.h"
24#include "ScopedStringChars.h"
25#include "ScopedUtfChars.h"
26#include "android_util_Binder.h"
27#include <utils/misc.h>
28#include <android_runtime/AndroidRuntime.h>
29#include <utils/Log.h>
30
31#include <androidfw/Asset.h>
32#include <androidfw/AssetManager.h>
33#include <androidfw/ResourceTypes.h>
34
35#include <private/android_filesystem_config.h> // for AID_SYSTEM
36
37#include "core_jni_helpers.h"
38
39#include <stdio.h>
40#include <sys/types.h>
41#include <sys/wait.h>
42
43#include <linux/capability.h>
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
1014static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1015                                                          jlong themeToken,
1016                                                          jint defStyleAttr,
1017                                                          jint defStyleRes,
1018                                                          jintArray inValues,
1019                                                          jintArray attrs,
1020                                                          jintArray outValues,
1021                                                          jintArray outIndices)
1022{
1023    if (themeToken == 0) {
1024        jniThrowNullPointerException(env, "theme token");
1025        return JNI_FALSE;
1026    }
1027    if (attrs == NULL) {
1028        jniThrowNullPointerException(env, "attrs");
1029        return JNI_FALSE;
1030    }
1031    if (outValues == NULL) {
1032        jniThrowNullPointerException(env, "out values");
1033        return JNI_FALSE;
1034    }
1035
1036    if (kDebugStyles) {
1037        ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
1038                themeToken, defStyleAttr, defStyleRes);
1039    }
1040
1041    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1042    const ResTable& res = theme->getResTable();
1043    ResTable_config config;
1044    Res_value value;
1045
1046    const jsize NI = env->GetArrayLength(attrs);
1047    const jsize NV = env->GetArrayLength(outValues);
1048    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1049        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1050        return JNI_FALSE;
1051    }
1052
1053    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1054    if (src == NULL) {
1055        return JNI_FALSE;
1056    }
1057
1058    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1059    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1060
1061    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1062    jint* dest = baseDest;
1063    if (dest == NULL) {
1064        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1065        return JNI_FALSE;
1066    }
1067
1068    jint* indices = NULL;
1069    int indicesIdx = 0;
1070    if (outIndices != NULL) {
1071        if (env->GetArrayLength(outIndices) > NI) {
1072            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1073        }
1074    }
1075
1076    // Load default style from attribute, if specified...
1077    uint32_t defStyleBagTypeSetFlags = 0;
1078    if (defStyleAttr != 0) {
1079        Res_value value;
1080        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1081            if (value.dataType == Res_value::TYPE_REFERENCE) {
1082                defStyleRes = value.data;
1083            }
1084        }
1085    }
1086
1087    // Now lock down the resource object and start pulling stuff from it.
1088    res.lock();
1089
1090    // Retrieve the default style bag, if requested.
1091    const ResTable::bag_entry* defStyleEnt = NULL;
1092    uint32_t defStyleTypeSetFlags = 0;
1093    ssize_t bagOff = defStyleRes != 0
1094            ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
1095    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1096    const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1097        (bagOff >= 0 ? bagOff : 0);;
1098
1099    // Now iterate through all of the attributes that the client has requested,
1100    // filling in each with whatever data we can find.
1101    ssize_t block = 0;
1102    uint32_t typeSetFlags;
1103    for (jsize ii=0; ii<NI; ii++) {
1104        const uint32_t curIdent = (uint32_t)src[ii];
1105
1106        if (kDebugStyles) {
1107            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1108        }
1109
1110        // Try to find a value for this attribute...  we prioritize values
1111        // coming from, first XML attributes, then XML style, then default
1112        // style, and finally the theme.
1113        value.dataType = Res_value::TYPE_NULL;
1114        value.data = 0;
1115        typeSetFlags = 0;
1116        config.density = 0;
1117
1118        // Retrieve the current input value if available.
1119        if (NSV > 0 && srcValues[ii] != 0) {
1120            block = -1;
1121            value.dataType = Res_value::TYPE_ATTRIBUTE;
1122            value.data = srcValues[ii];
1123            if (kDebugStyles) {
1124                ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
1125            }
1126        }
1127
1128        // Skip through the default style values until the end or the next possible match.
1129        while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1130            defStyleEnt++;
1131        }
1132        // Retrieve the current default style attribute if it matches, and step to next.
1133        if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1134            if (value.dataType == Res_value::TYPE_NULL) {
1135                block = defStyleEnt->stringBlock;
1136                typeSetFlags = defStyleTypeSetFlags;
1137                value = defStyleEnt->map.value;
1138                if (kDebugStyles) {
1139                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1140                }
1141            }
1142            defStyleEnt++;
1143        }
1144
1145        uint32_t resid = 0;
1146        if (value.dataType != Res_value::TYPE_NULL) {
1147            // Take care of resolving the found resource to its final value.
1148            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1149                    &resid, &typeSetFlags, &config);
1150            if (newBlock >= 0) block = newBlock;
1151            if (kDebugStyles) {
1152                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1153            }
1154        } else {
1155            // If we still don't have a value for this attribute, try to find
1156            // it in the theme!
1157            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1158            if (newBlock >= 0) {
1159                if (kDebugStyles) {
1160                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1161                }
1162                newBlock = res.resolveReference(&value, block, &resid,
1163                        &typeSetFlags, &config);
1164                if (kThrowOnBadId) {
1165                    if (newBlock == BAD_INDEX) {
1166                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1167                        return JNI_FALSE;
1168                    }
1169                }
1170                if (newBlock >= 0) block = newBlock;
1171                if (kDebugStyles) {
1172                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1173                }
1174            }
1175        }
1176
1177        // Deal with the special @null value -- it turns back to TYPE_NULL.
1178        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1179            if (kDebugStyles) {
1180                ALOGI("-> Setting to @null!");
1181            }
1182            value.dataType = Res_value::TYPE_NULL;
1183            block = -1;
1184        }
1185
1186        if (kDebugStyles) {
1187            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
1188                  value.data);
1189        }
1190
1191        // Write the final value back to Java.
1192        dest[STYLE_TYPE] = value.dataType;
1193        dest[STYLE_DATA] = value.data;
1194        dest[STYLE_ASSET_COOKIE] =
1195            block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1196        dest[STYLE_RESOURCE_ID] = resid;
1197        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1198        dest[STYLE_DENSITY] = config.density;
1199
1200        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1201            indicesIdx++;
1202            indices[indicesIdx] = ii;
1203        }
1204
1205        dest += STYLE_NUM_ENTRIES;
1206    }
1207
1208    res.unlock();
1209
1210    if (indices != NULL) {
1211        indices[0] = indicesIdx;
1212        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1213    }
1214    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1215    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1216    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1217
1218    return JNI_TRUE;
1219}
1220
1221static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1222                                                        jlong themeToken,
1223                                                        jint defStyleAttr,
1224                                                        jint defStyleRes,
1225                                                        jlong xmlParserToken,
1226                                                        jintArray attrs,
1227                                                        jintArray outValues,
1228                                                        jintArray outIndices)
1229{
1230    if (themeToken == 0) {
1231        jniThrowNullPointerException(env, "theme token");
1232        return JNI_FALSE;
1233    }
1234    if (attrs == NULL) {
1235        jniThrowNullPointerException(env, "attrs");
1236        return JNI_FALSE;
1237    }
1238    if (outValues == NULL) {
1239        jniThrowNullPointerException(env, "out values");
1240        return JNI_FALSE;
1241    }
1242
1243    if (kDebugStyles) {
1244    ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
1245          themeToken, defStyleAttr, defStyleRes, xmlParserToken);
1246    }
1247
1248    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1249    const ResTable& res = theme->getResTable();
1250    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1251    ResTable_config config;
1252    Res_value value;
1253
1254    const jsize NI = env->GetArrayLength(attrs);
1255    const jsize NV = env->GetArrayLength(outValues);
1256    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1257        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1258        return JNI_FALSE;
1259    }
1260
1261    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1262    if (src == NULL) {
1263        return JNI_FALSE;
1264    }
1265
1266    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1267    jint* dest = baseDest;
1268    if (dest == NULL) {
1269        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1270        return JNI_FALSE;
1271    }
1272
1273    jint* indices = NULL;
1274    int indicesIdx = 0;
1275    if (outIndices != NULL) {
1276        if (env->GetArrayLength(outIndices) > NI) {
1277            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1278        }
1279    }
1280
1281    // Load default style from attribute, if specified...
1282    uint32_t defStyleBagTypeSetFlags = 0;
1283    if (defStyleAttr != 0) {
1284        Res_value value;
1285        if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1286            if (value.dataType == Res_value::TYPE_REFERENCE) {
1287                defStyleRes = value.data;
1288            }
1289        }
1290    }
1291
1292    // Retrieve the style class associated with the current XML tag.
1293    int style = 0;
1294    uint32_t styleBagTypeSetFlags = 0;
1295    if (xmlParser != NULL) {
1296        ssize_t idx = xmlParser->indexOfStyle();
1297        if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1298            if (value.dataType == value.TYPE_ATTRIBUTE) {
1299                if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1300                    value.dataType = Res_value::TYPE_NULL;
1301                }
1302            }
1303            if (value.dataType == value.TYPE_REFERENCE) {
1304                style = value.data;
1305            }
1306        }
1307    }
1308
1309    // Now lock down the resource object and start pulling stuff from it.
1310    res.lock();
1311
1312    // Retrieve the default style bag, if requested.
1313    const ResTable::bag_entry* defStyleEnt = NULL;
1314    uint32_t defStyleTypeSetFlags = 0;
1315    ssize_t bagOff = defStyleRes != 0
1316            ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
1317    defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1318    const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
1319        (bagOff >= 0 ? bagOff : 0);
1320
1321    // Retrieve the style class bag, if requested.
1322    const ResTable::bag_entry* styleEnt = NULL;
1323    uint32_t styleTypeSetFlags = 0;
1324    bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
1325    styleTypeSetFlags |= styleBagTypeSetFlags;
1326    const ResTable::bag_entry* endStyleEnt = styleEnt +
1327        (bagOff >= 0 ? bagOff : 0);
1328
1329    // Retrieve the XML attributes, if requested.
1330    const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
1331    jsize ix=0;
1332    uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
1333
1334    static const ssize_t kXmlBlock = 0x10000000;
1335
1336    // Now iterate through all of the attributes that the client has requested,
1337    // filling in each with whatever data we can find.
1338    ssize_t block = 0;
1339    uint32_t typeSetFlags;
1340    for (jsize ii=0; ii<NI; ii++) {
1341        const uint32_t curIdent = (uint32_t)src[ii];
1342
1343        if (kDebugStyles) {
1344            ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
1345        }
1346
1347        // Try to find a value for this attribute...  we prioritize values
1348        // coming from, first XML attributes, then XML style, then default
1349        // style, and finally the theme.
1350        value.dataType = Res_value::TYPE_NULL;
1351        value.data = 0;
1352        typeSetFlags = 0;
1353        config.density = 0;
1354
1355        // Skip through XML attributes until the end or the next possible match.
1356        while (ix < NX && curIdent > curXmlAttr) {
1357            ix++;
1358            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1359        }
1360        // Retrieve the current XML attribute if it matches, and step to next.
1361        if (ix < NX && curIdent == curXmlAttr) {
1362            block = kXmlBlock;
1363            xmlParser->getAttributeValue(ix, &value);
1364            ix++;
1365            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1366            if (kDebugStyles) {
1367                ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
1368            }
1369        }
1370
1371        // Skip through the style values until the end or the next possible match.
1372        while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1373            styleEnt++;
1374        }
1375        // Retrieve the current style attribute if it matches, and step to next.
1376        if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1377            if (value.dataType == Res_value::TYPE_NULL) {
1378                block = styleEnt->stringBlock;
1379                typeSetFlags = styleTypeSetFlags;
1380                value = styleEnt->map.value;
1381                if (kDebugStyles) {
1382                    ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
1383                }
1384            }
1385            styleEnt++;
1386        }
1387
1388        // Skip through the default style values until the end or the next possible match.
1389        while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1390            defStyleEnt++;
1391        }
1392        // Retrieve the current default style attribute if it matches, and step to next.
1393        if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1394            if (value.dataType == Res_value::TYPE_NULL) {
1395                block = defStyleEnt->stringBlock;
1396                typeSetFlags = defStyleTypeSetFlags;
1397                value = defStyleEnt->map.value;
1398                if (kDebugStyles) {
1399                    ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
1400                }
1401            }
1402            defStyleEnt++;
1403        }
1404
1405        uint32_t resid = 0;
1406        if (value.dataType != Res_value::TYPE_NULL) {
1407            // Take care of resolving the found resource to its final value.
1408            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1409                    &resid, &typeSetFlags, &config);
1410            if (newBlock >= 0) block = newBlock;
1411            if (kDebugStyles) {
1412                ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
1413            }
1414        } else {
1415            // If we still don't have a value for this attribute, try to find
1416            // it in the theme!
1417            ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1418            if (newBlock >= 0) {
1419                if (kDebugStyles) {
1420                    ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1421                }
1422                newBlock = res.resolveReference(&value, block, &resid,
1423                        &typeSetFlags, &config);
1424                if (kThrowOnBadId) {
1425                    if (newBlock == BAD_INDEX) {
1426                        jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1427                        return JNI_FALSE;
1428                    }
1429                }
1430                if (newBlock >= 0) block = newBlock;
1431                if (kDebugStyles) {
1432                    ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
1433                }
1434            }
1435        }
1436
1437        // Deal with the special @null value -- it turns back to TYPE_NULL.
1438        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1439            if (kDebugStyles) {
1440                ALOGI("-> Setting to @null!");
1441            }
1442            value.dataType = Res_value::TYPE_NULL;
1443            block = kXmlBlock;
1444        }
1445
1446        if (kDebugStyles) {
1447            ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
1448        }
1449
1450        // Write the final value back to Java.
1451        dest[STYLE_TYPE] = value.dataType;
1452        dest[STYLE_DATA] = value.data;
1453        dest[STYLE_ASSET_COOKIE] =
1454            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1455        dest[STYLE_RESOURCE_ID] = resid;
1456        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1457        dest[STYLE_DENSITY] = config.density;
1458
1459        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1460            indicesIdx++;
1461            indices[indicesIdx] = ii;
1462        }
1463
1464        dest += STYLE_NUM_ENTRIES;
1465    }
1466
1467    res.unlock();
1468
1469    if (indices != NULL) {
1470        indices[0] = indicesIdx;
1471        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1472    }
1473    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1474    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1475
1476    return JNI_TRUE;
1477}
1478
1479static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1480                                                        jlong xmlParserToken,
1481                                                        jintArray attrs,
1482                                                        jintArray outValues,
1483                                                        jintArray outIndices)
1484{
1485    if (xmlParserToken == 0) {
1486        jniThrowNullPointerException(env, "xmlParserToken");
1487        return JNI_FALSE;
1488    }
1489    if (attrs == NULL) {
1490        jniThrowNullPointerException(env, "attrs");
1491        return JNI_FALSE;
1492    }
1493    if (outValues == NULL) {
1494        jniThrowNullPointerException(env, "out values");
1495        return JNI_FALSE;
1496    }
1497
1498    AssetManager* am = assetManagerForJavaObject(env, clazz);
1499    if (am == NULL) {
1500        return JNI_FALSE;
1501    }
1502    const ResTable& res(am->getResources());
1503    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1504    ResTable_config config;
1505    Res_value value;
1506
1507    const jsize NI = env->GetArrayLength(attrs);
1508    const jsize NV = env->GetArrayLength(outValues);
1509    if (NV < (NI*STYLE_NUM_ENTRIES)) {
1510        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1511        return JNI_FALSE;
1512    }
1513
1514    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1515    if (src == NULL) {
1516        return JNI_FALSE;
1517    }
1518
1519    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1520    jint* dest = baseDest;
1521    if (dest == NULL) {
1522        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1523        return JNI_FALSE;
1524    }
1525
1526    jint* indices = NULL;
1527    int indicesIdx = 0;
1528    if (outIndices != NULL) {
1529        if (env->GetArrayLength(outIndices) > NI) {
1530            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1531        }
1532    }
1533
1534    // Now lock down the resource object and start pulling stuff from it.
1535    res.lock();
1536
1537    // Retrieve the XML attributes, if requested.
1538    const jsize NX = xmlParser->getAttributeCount();
1539    jsize ix=0;
1540    uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1541
1542    static const ssize_t kXmlBlock = 0x10000000;
1543
1544    // Now iterate through all of the attributes that the client has requested,
1545    // filling in each with whatever data we can find.
1546    ssize_t block = 0;
1547    uint32_t typeSetFlags;
1548    for (jsize ii=0; ii<NI; ii++) {
1549        const uint32_t curIdent = (uint32_t)src[ii];
1550
1551        // Try to find a value for this attribute...
1552        value.dataType = Res_value::TYPE_NULL;
1553        value.data = 0;
1554        typeSetFlags = 0;
1555        config.density = 0;
1556
1557        // Skip through XML attributes until the end or the next possible match.
1558        while (ix < NX && curIdent > curXmlAttr) {
1559            ix++;
1560            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1561        }
1562        // Retrieve the current XML attribute if it matches, and step to next.
1563        if (ix < NX && curIdent == curXmlAttr) {
1564            block = kXmlBlock;
1565            xmlParser->getAttributeValue(ix, &value);
1566            ix++;
1567            curXmlAttr = xmlParser->getAttributeNameResID(ix);
1568        }
1569
1570        //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1571        uint32_t resid = 0;
1572        if (value.dataType != Res_value::TYPE_NULL) {
1573            // Take care of resolving the found resource to its final value.
1574            //printf("Resolving attribute reference\n");
1575            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1576                    &typeSetFlags, &config);
1577            if (kThrowOnBadId) {
1578                if (newBlock == BAD_INDEX) {
1579                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1580                    return JNI_FALSE;
1581                }
1582            }
1583            if (newBlock >= 0) block = newBlock;
1584        }
1585
1586        // Deal with the special @null value -- it turns back to TYPE_NULL.
1587        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1588            value.dataType = Res_value::TYPE_NULL;
1589        }
1590
1591        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1592
1593        // Write the final value back to Java.
1594        dest[STYLE_TYPE] = value.dataType;
1595        dest[STYLE_DATA] = value.data;
1596        dest[STYLE_ASSET_COOKIE] =
1597            block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1598        dest[STYLE_RESOURCE_ID] = resid;
1599        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1600        dest[STYLE_DENSITY] = config.density;
1601
1602        if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1603            indicesIdx++;
1604            indices[indicesIdx] = ii;
1605        }
1606
1607        dest += STYLE_NUM_ENTRIES;
1608    }
1609
1610    res.unlock();
1611
1612    if (indices != NULL) {
1613        indices[0] = indicesIdx;
1614        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1615    }
1616
1617    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1618    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1619
1620    return JNI_TRUE;
1621}
1622
1623static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1624                                                       jint id)
1625{
1626    AssetManager* am = assetManagerForJavaObject(env, clazz);
1627    if (am == NULL) {
1628        return 0;
1629    }
1630    const ResTable& res(am->getResources());
1631
1632    res.lock();
1633    const ResTable::bag_entry* defStyleEnt = NULL;
1634    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1635    res.unlock();
1636
1637    return static_cast<jint>(bagOff);
1638}
1639
1640static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1641                                                        jint id,
1642                                                        jintArray outValues)
1643{
1644    if (outValues == NULL) {
1645        jniThrowNullPointerException(env, "out values");
1646        return JNI_FALSE;
1647    }
1648
1649    AssetManager* am = assetManagerForJavaObject(env, clazz);
1650    if (am == NULL) {
1651        return JNI_FALSE;
1652    }
1653    const ResTable& res(am->getResources());
1654    ResTable_config config;
1655    Res_value value;
1656    ssize_t block;
1657
1658    const jsize NV = env->GetArrayLength(outValues);
1659
1660    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1661    jint* dest = baseDest;
1662    if (dest == NULL) {
1663        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1664        return JNI_FALSE;
1665    }
1666
1667    // Now lock down the resource object and start pulling stuff from it.
1668    res.lock();
1669
1670    const ResTable::bag_entry* arrayEnt = NULL;
1671    uint32_t arrayTypeSetFlags = 0;
1672    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1673    const ResTable::bag_entry* endArrayEnt = arrayEnt +
1674        (bagOff >= 0 ? bagOff : 0);
1675
1676    int i = 0;
1677    uint32_t typeSetFlags;
1678    while (i < NV && arrayEnt < endArrayEnt) {
1679        block = arrayEnt->stringBlock;
1680        typeSetFlags = arrayTypeSetFlags;
1681        config.density = 0;
1682        value = arrayEnt->map.value;
1683
1684        uint32_t resid = 0;
1685        if (value.dataType != Res_value::TYPE_NULL) {
1686            // Take care of resolving the found resource to its final value.
1687            //printf("Resolving attribute reference\n");
1688            ssize_t newBlock = res.resolveReference(&value, block, &resid,
1689                    &typeSetFlags, &config);
1690            if (kThrowOnBadId) {
1691                if (newBlock == BAD_INDEX) {
1692                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1693                    return JNI_FALSE;
1694                }
1695            }
1696            if (newBlock >= 0) block = newBlock;
1697        }
1698
1699        // Deal with the special @null value -- it turns back to TYPE_NULL.
1700        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1701            value.dataType = Res_value::TYPE_NULL;
1702        }
1703
1704        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1705
1706        // Write the final value back to Java.
1707        dest[STYLE_TYPE] = value.dataType;
1708        dest[STYLE_DATA] = value.data;
1709        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1710        dest[STYLE_RESOURCE_ID] = resid;
1711        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1712        dest[STYLE_DENSITY] = config.density;
1713        dest += STYLE_NUM_ENTRIES;
1714        i+= STYLE_NUM_ENTRIES;
1715        arrayEnt++;
1716    }
1717
1718    i /= STYLE_NUM_ENTRIES;
1719
1720    res.unlock();
1721
1722    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1723
1724    return i;
1725}
1726
1727static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1728                                                         jint cookie,
1729                                                         jstring fileName)
1730{
1731    AssetManager* am = assetManagerForJavaObject(env, clazz);
1732    if (am == NULL) {
1733        return 0;
1734    }
1735
1736    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1737
1738    ScopedUtfChars fileName8(env, fileName);
1739    if (fileName8.c_str() == NULL) {
1740        return 0;
1741    }
1742
1743    int32_t assetCookie = static_cast<int32_t>(cookie);
1744    Asset* a = assetCookie
1745        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1746        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1747
1748    if (a == NULL) {
1749        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1750        return 0;
1751    }
1752
1753    const DynamicRefTable* dynamicRefTable =
1754            am->getResources().getDynamicRefTableForCookie(assetCookie);
1755    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1756    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1757    a->close();
1758    delete a;
1759
1760    if (err != NO_ERROR) {
1761        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1762        return 0;
1763    }
1764
1765    return reinterpret_cast<jlong>(block);
1766}
1767
1768static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1769                                                                 jint arrayResId)
1770{
1771    AssetManager* am = assetManagerForJavaObject(env, clazz);
1772    if (am == NULL) {
1773        return NULL;
1774    }
1775    const ResTable& res(am->getResources());
1776
1777    const ResTable::bag_entry* startOfBag;
1778    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1779    if (N < 0) {
1780        return NULL;
1781    }
1782
1783    jintArray array = env->NewIntArray(N * 2);
1784    if (array == NULL) {
1785        res.unlockBag(startOfBag);
1786        return NULL;
1787    }
1788
1789    Res_value value;
1790    const ResTable::bag_entry* bag = startOfBag;
1791    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1792        jint stringIndex = -1;
1793        jint stringBlock = 0;
1794        value = bag->map.value;
1795
1796        // Take care of resolving the found resource to its final value.
1797        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1798        if (value.dataType == Res_value::TYPE_STRING) {
1799            stringIndex = value.data;
1800        }
1801
1802        if (kThrowOnBadId) {
1803            if (stringBlock == BAD_INDEX) {
1804                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1805                return array;
1806            }
1807        }
1808
1809        //todo: It might be faster to allocate a C array to contain
1810        //      the blocknums and indices, put them in there and then
1811        //      do just one SetIntArrayRegion()
1812        env->SetIntArrayRegion(array, j, 1, &stringBlock);
1813        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1814        j = j + 2;
1815    }
1816    res.unlockBag(startOfBag);
1817    return array;
1818}
1819
1820static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1821                                                                        jint arrayResId)
1822{
1823    AssetManager* am = assetManagerForJavaObject(env, clazz);
1824    if (am == NULL) {
1825        return NULL;
1826    }
1827    const ResTable& res(am->getResources());
1828
1829    const ResTable::bag_entry* startOfBag;
1830    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1831    if (N < 0) {
1832        return NULL;
1833    }
1834
1835    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1836    if (env->ExceptionCheck()) {
1837        res.unlockBag(startOfBag);
1838        return NULL;
1839    }
1840
1841    Res_value value;
1842    const ResTable::bag_entry* bag = startOfBag;
1843    size_t strLen = 0;
1844    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1845        value = bag->map.value;
1846        jstring str = NULL;
1847
1848        // Take care of resolving the found resource to its final value.
1849        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1850        if (kThrowOnBadId) {
1851            if (block == BAD_INDEX) {
1852                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1853                return array;
1854            }
1855        }
1856        if (value.dataType == Res_value::TYPE_STRING) {
1857            const ResStringPool* pool = res.getTableStringBlock(block);
1858            const char* str8 = pool->string8At(value.data, &strLen);
1859            if (str8 != NULL) {
1860                str = env->NewStringUTF(str8);
1861            } else {
1862                const char16_t* str16 = pool->stringAt(value.data, &strLen);
1863                str = env->NewString(reinterpret_cast<const jchar*>(str16),
1864                                     strLen);
1865            }
1866
1867            // If one of our NewString{UTF} calls failed due to memory, an
1868            // exception will be pending.
1869            if (env->ExceptionCheck()) {
1870                res.unlockBag(startOfBag);
1871                return NULL;
1872            }
1873
1874            env->SetObjectArrayElement(array, i, str);
1875
1876            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1877            // If we have a large amount of strings in our array, we might
1878            // overflow the local reference table of the VM.
1879            env->DeleteLocalRef(str);
1880        }
1881    }
1882    res.unlockBag(startOfBag);
1883    return array;
1884}
1885
1886static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1887                                                                        jint arrayResId)
1888{
1889    AssetManager* am = assetManagerForJavaObject(env, clazz);
1890    if (am == NULL) {
1891        return NULL;
1892    }
1893    const ResTable& res(am->getResources());
1894
1895    const ResTable::bag_entry* startOfBag;
1896    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1897    if (N < 0) {
1898        return NULL;
1899    }
1900
1901    jintArray array = env->NewIntArray(N);
1902    if (array == NULL) {
1903        res.unlockBag(startOfBag);
1904        return NULL;
1905    }
1906
1907    Res_value value;
1908    const ResTable::bag_entry* bag = startOfBag;
1909    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1910        value = bag->map.value;
1911
1912        // Take care of resolving the found resource to its final value.
1913        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1914        if (kThrowOnBadId) {
1915            if (block == BAD_INDEX) {
1916                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1917                return array;
1918            }
1919        }
1920        if (value.dataType >= Res_value::TYPE_FIRST_INT
1921                && value.dataType <= Res_value::TYPE_LAST_INT) {
1922            int intVal = value.data;
1923            env->SetIntArrayRegion(array, i, 1, &intVal);
1924        }
1925    }
1926    res.unlockBag(startOfBag);
1927    return array;
1928}
1929
1930static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1931                                                                 jint styleId)
1932{
1933    AssetManager* am = assetManagerForJavaObject(env, clazz);
1934    if (am == NULL) {
1935        return NULL;
1936    }
1937    const ResTable& res(am->getResources());
1938
1939    const ResTable::bag_entry* startOfBag;
1940    const ssize_t N = res.lockBag(styleId, &startOfBag);
1941    if (N < 0) {
1942        return NULL;
1943    }
1944
1945    jintArray array = env->NewIntArray(N);
1946    if (array == NULL) {
1947        res.unlockBag(startOfBag);
1948        return NULL;
1949    }
1950
1951    const ResTable::bag_entry* bag = startOfBag;
1952    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1953        int resourceId = bag->map.name.ident;
1954        env->SetIntArrayRegion(array, i, 1, &resourceId);
1955    }
1956    res.unlockBag(startOfBag);
1957    return array;
1958}
1959
1960static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1961{
1962    if (isSystem) {
1963        verifySystemIdmaps();
1964    }
1965    AssetManager* am = new AssetManager();
1966    if (am == NULL) {
1967        jniThrowException(env, "java/lang/OutOfMemoryError", "");
1968        return;
1969    }
1970
1971    am->addDefaultAssets();
1972
1973    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1974    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1975}
1976
1977static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1978{
1979    AssetManager* am = (AssetManager*)
1980        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1981    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1982    if (am != NULL) {
1983        delete am;
1984        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
1985    }
1986}
1987
1988static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1989{
1990    return Asset::getGlobalCount();
1991}
1992
1993static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1994{
1995    String8 alloc = Asset::getAssetAllocations();
1996    if (alloc.length() <= 0) {
1997        return NULL;
1998    }
1999
2000    jstring str = env->NewStringUTF(alloc.string());
2001    return str;
2002}
2003
2004static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2005{
2006    return AssetManager::getGlobalCount();
2007}
2008
2009// ----------------------------------------------------------------------------
2010
2011/*
2012 * JNI registration.
2013 */
2014static JNINativeMethod gAssetManagerMethods[] = {
2015    /* name, signature, funcPtr */
2016
2017    // Basic asset stuff.
2018    { "openAsset",      "(Ljava/lang/String;I)J",
2019        (void*) android_content_AssetManager_openAsset },
2020    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2021        (void*) android_content_AssetManager_openAssetFd },
2022    { "openNonAssetNative", "(ILjava/lang/String;I)J",
2023        (void*) android_content_AssetManager_openNonAssetNative },
2024    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2025        (void*) android_content_AssetManager_openNonAssetFdNative },
2026    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
2027        (void*) android_content_AssetManager_list },
2028    { "destroyAsset",   "(J)V",
2029        (void*) android_content_AssetManager_destroyAsset },
2030    { "readAssetChar",  "(J)I",
2031        (void*) android_content_AssetManager_readAssetChar },
2032    { "readAsset",      "(J[BII)I",
2033        (void*) android_content_AssetManager_readAsset },
2034    { "seekAsset",      "(JJI)J",
2035        (void*) android_content_AssetManager_seekAsset },
2036    { "getAssetLength", "(J)J",
2037        (void*) android_content_AssetManager_getAssetLength },
2038    { "getAssetRemainingLength", "(J)J",
2039        (void*) android_content_AssetManager_getAssetRemainingLength },
2040    { "addAssetPathNative", "(Ljava/lang/String;)I",
2041        (void*) android_content_AssetManager_addAssetPath },
2042    { "addOverlayPath",   "(Ljava/lang/String;)I",
2043        (void*) android_content_AssetManager_addOverlayPath },
2044    { "isUpToDate",     "()Z",
2045        (void*) android_content_AssetManager_isUpToDate },
2046
2047    // Resources.
2048    { "setLocale",      "(Ljava/lang/String;)V",
2049        (void*) android_content_AssetManager_setLocale },
2050    { "getLocales",      "()[Ljava/lang/String;",
2051        (void*) android_content_AssetManager_getLocales },
2052    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2053        (void*) android_content_AssetManager_setConfiguration },
2054    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2055        (void*) android_content_AssetManager_getResourceIdentifier },
2056    { "getResourceName","(I)Ljava/lang/String;",
2057        (void*) android_content_AssetManager_getResourceName },
2058    { "getResourcePackageName","(I)Ljava/lang/String;",
2059        (void*) android_content_AssetManager_getResourcePackageName },
2060    { "getResourceTypeName","(I)Ljava/lang/String;",
2061        (void*) android_content_AssetManager_getResourceTypeName },
2062    { "getResourceEntryName","(I)Ljava/lang/String;",
2063        (void*) android_content_AssetManager_getResourceEntryName },
2064    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2065        (void*) android_content_AssetManager_loadResourceValue },
2066    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2067        (void*) android_content_AssetManager_loadResourceBagValue },
2068    { "getStringBlockCount","()I",
2069        (void*) android_content_AssetManager_getStringBlockCount },
2070    { "getNativeStringBlock","(I)J",
2071        (void*) android_content_AssetManager_getNativeStringBlock },
2072    { "getCookieName","(I)Ljava/lang/String;",
2073        (void*) android_content_AssetManager_getCookieName },
2074    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2075        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2076
2077    // Themes.
2078    { "newTheme", "()J",
2079        (void*) android_content_AssetManager_newTheme },
2080    { "deleteTheme", "(J)V",
2081        (void*) android_content_AssetManager_deleteTheme },
2082    { "applyThemeStyle", "(JIZ)V",
2083        (void*) android_content_AssetManager_applyThemeStyle },
2084    { "copyTheme", "(JJ)V",
2085        (void*) android_content_AssetManager_copyTheme },
2086    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2087        (void*) android_content_AssetManager_loadThemeAttributeValue },
2088    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2089        (void*) android_content_AssetManager_dumpTheme },
2090    { "applyStyle","(JIIJ[I[I[I)Z",
2091        (void*) android_content_AssetManager_applyStyle },
2092    { "resolveAttrs","(JII[I[I[I[I)Z",
2093        (void*) android_content_AssetManager_resolveAttrs },
2094    { "retrieveAttributes","(J[I[I[I)Z",
2095        (void*) android_content_AssetManager_retrieveAttributes },
2096    { "getArraySize","(I)I",
2097        (void*) android_content_AssetManager_getArraySize },
2098    { "retrieveArray","(I[I)I",
2099        (void*) android_content_AssetManager_retrieveArray },
2100
2101    // XML files.
2102    { "openXmlAssetNative", "(ILjava/lang/String;)J",
2103        (void*) android_content_AssetManager_openXmlAssetNative },
2104
2105    // Arrays.
2106    { "getArrayStringResource","(I)[Ljava/lang/String;",
2107        (void*) android_content_AssetManager_getArrayStringResource },
2108    { "getArrayStringInfo","(I)[I",
2109        (void*) android_content_AssetManager_getArrayStringInfo },
2110    { "getArrayIntResource","(I)[I",
2111        (void*) android_content_AssetManager_getArrayIntResource },
2112    { "getStyleAttributes","(I)[I",
2113        (void*) android_content_AssetManager_getStyleAttributes },
2114
2115    // Bookkeeping.
2116    { "init",           "(Z)V",
2117        (void*) android_content_AssetManager_init },
2118    { "destroy",        "()V",
2119        (void*) android_content_AssetManager_destroy },
2120    { "getGlobalAssetCount", "()I",
2121        (void*) android_content_AssetManager_getGlobalAssetCount },
2122    { "getAssetAllocations", "()Ljava/lang/String;",
2123        (void*) android_content_AssetManager_getAssetAllocations },
2124    { "getGlobalAssetManagerCount", "()I",
2125        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
2126};
2127
2128int register_android_content_AssetManager(JNIEnv* env)
2129{
2130    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
2131    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
2132    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
2133    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
2134                                                 "Ljava/lang/CharSequence;");
2135    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
2136    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
2137    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
2138                                                                 "changingConfigurations", "I");
2139    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
2140
2141    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
2142    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
2143                                                      "Landroid/os/ParcelFileDescriptor;");
2144    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
2145    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
2146
2147    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
2148    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
2149
2150    jclass stringClass = FindClassOrDie(env, "java/lang/String");
2151    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
2152
2153    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
2154    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
2155    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
2156                                                       "<init>", "()V");
2157    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
2158                                               "(ILjava/lang/Object;)V");
2159
2160    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
2161                                NELEM(gAssetManagerMethods));
2162}
2163
2164}; // namespace android
2165