OSDN Git Service

am 1f3c7f3f: am f18ceefc: am cd6e00c6: Merge changes from topic \'layoutlib-api-15...
[android-x86/frameworks-base.git] / core / jni / android_util_AssetManager.cpp
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
44 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
45 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
46
47
48 namespace android {
49
50 static const bool kThrowOnBadId = false;
51 static const bool kDebugStyles = false;
52
53 // ----------------------------------------------------------------------------
54
55 static 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
66 static struct assetfiledescriptor_offsets_t
67 {
68     jfieldID mFd;
69     jfieldID mStartOffset;
70     jfieldID mLength;
71 } gAssetFileDescriptorOffsets;
72
73 static struct assetmanager_offsets_t
74 {
75     jfieldID mObject;
76 } gAssetManagerOffsets;
77
78 static struct sparsearray_offsets_t
79 {
80     jclass classObject;
81     jmethodID constructor;
82     jmethodID put;
83 } gSparseArrayOffsets;
84
85 jclass g_stringClass = NULL;
86
87 // ----------------------------------------------------------------------------
88
89 enum {
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
99 static 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
103 jint 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.
122 static 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
181 AssetManager* 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
192 static 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
226 static 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
258 static 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
285 static 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
323 static 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
354 static 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
399 static 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
414 static 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
429 static 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
462 static 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
477 static 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
490 static 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
503 static 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
522 static 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
541 static 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
550 static 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
566 static 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
596 static 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
640 static 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
683 static 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
726 static 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
746 static 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
770 static 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
794 static 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
837 static 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
888 static 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
897 static 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
907 static 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
923 static 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
946 static 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
955 static 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
962 static 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
971 static 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
979 static 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
1002 static 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
1014 class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1015 public:
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
1024 private:
1025     const ResXMLParser* mParser;
1026 };
1027
1028 class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1029 public:
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
1038 static 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
1241 static 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
1495 static 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
1640 static 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
1657 static 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
1745 static 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
1786 static 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
1838 static 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
1904 static 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
1948 static 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
1978 static 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
1995 static 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
2006 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2007 {
2008     return Asset::getGlobalCount();
2009 }
2010
2011 static 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
2022 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
2023 {
2024     return AssetManager::getGlobalCount();
2025 }
2026
2027 // ----------------------------------------------------------------------------
2028
2029 /*
2030  * JNI registration.
2031  */
2032 static 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     { "addOverlayPathNative",   "(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
2146 int 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