OSDN Git Service

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