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 
copyValue(JNIEnv * env,jobject outValue,const ResTable * table,const Res_value & value,uint32_t ref,ssize_t block,uint32_t typeSpecFlags,ResTable_config * config)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.
verifySystemIdmaps()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
assetManagerForJavaObject(JNIEnv * env,jobject obj)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 
android_content_AssetManager_openAsset(JNIEnv * env,jobject clazz,jstring fileName,jint mode)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 
returnParcelFileDescriptor(JNIEnv * env,Asset * a,jlongArray outOffsets)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 
android_content_AssetManager_openAssetFd(JNIEnv * env,jobject clazz,jstring fileName,jlongArray outOffsets)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 
android_content_AssetManager_openNonAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jint mode)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 
android_content_AssetManager_openNonAssetFdNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jlongArray outOffsets)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 
android_content_AssetManager_list(JNIEnv * env,jobject clazz,jstring fileName)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 
android_content_AssetManager_destroyAsset(JNIEnv * env,jobject clazz,jlong assetHandle)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 
android_content_AssetManager_readAssetChar(JNIEnv * env,jobject clazz,jlong assetHandle)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 
android_content_AssetManager_readAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jbyteArray bArray,jint off,jint len)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 
android_content_AssetManager_seekAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jlong offset,jint whence)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 
android_content_AssetManager_getAssetLength(JNIEnv * env,jobject clazz,jlong assetHandle)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 
android_content_AssetManager_getAssetRemainingLength(JNIEnv * env,jobject clazz,jlong assetHandle)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 
android_content_AssetManager_addAssetPath(JNIEnv * env,jobject clazz,jstring path)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 
android_content_AssetManager_addOverlayPath(JNIEnv * env,jobject clazz,jstring idmapPath)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 
android_content_AssetManager_isUpToDate(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_setLocale(JNIEnv * env,jobject clazz,jstring locale)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 
android_content_AssetManager_getLocales(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_setConfiguration(JNIEnv * env,jobject clazz,jint mcc,jint mnc,jstring locale,jint orientation,jint touchscreen,jint density,jint keyboard,jint keyboardHidden,jint navigation,jint screenWidth,jint screenHeight,jint smallestScreenWidthDp,jint screenWidthDp,jint screenHeightDp,jint screenLayout,jint uiMode,jint sdkVersion)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 
android_content_AssetManager_getResourceIdentifier(JNIEnv * env,jobject clazz,jstring name,jstring defType,jstring defPackage)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 
android_content_AssetManager_getResourceName(JNIEnv * env,jobject clazz,jint resid)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 
android_content_AssetManager_getResourcePackageName(JNIEnv * env,jobject clazz,jint resid)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 
android_content_AssetManager_getResourceTypeName(JNIEnv * env,jobject clazz,jint resid)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 
android_content_AssetManager_getResourceEntryName(JNIEnv * env,jobject clazz,jint resid)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 
android_content_AssetManager_loadResourceValue(JNIEnv * env,jobject clazz,jint ident,jshort density,jobject outValue,jboolean resolve)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 
android_content_AssetManager_loadResourceBagValue(JNIEnv * env,jobject clazz,jint ident,jint bagEntryId,jobject outValue,jboolean resolve)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 
android_content_AssetManager_getStringBlockCount(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_getNativeStringBlock(JNIEnv * env,jobject clazz,jint block)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 
android_content_AssetManager_getCookieName(JNIEnv * env,jobject clazz,jint cookie)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 
android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_newTheme(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_deleteTheme(JNIEnv * env,jobject clazz,jlong themeHandle)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 
android_content_AssetManager_applyThemeStyle(JNIEnv * env,jobject clazz,jlong themeHandle,jint styleRes,jboolean force)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 
android_content_AssetManager_copyTheme(JNIEnv * env,jobject clazz,jlong destHandle,jlong srcHandle)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 
android_content_AssetManager_clearTheme(JNIEnv * env,jobject clazz,jlong themeHandle)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 
android_content_AssetManager_loadThemeAttributeValue(JNIEnv * env,jobject clazz,jlong themeHandle,jint ident,jobject outValue,jboolean resolve)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 
android_content_AssetManager_getThemeChangingConfigurations(JNIEnv * env,jobject clazz,jlong themeHandle)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 
android_content_AssetManager_dumpTheme(JNIEnv * env,jobject clazz,jlong themeHandle,jint pri,jstring tag,jstring prefix)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:
XmlAttributeFinder(const ResXMLParser * parser)1040     XmlAttributeFinder(const ResXMLParser* parser)
1041         : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1042         , mParser(parser) {}
1043 
getAttribute(jsize index) const1044     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:
BagAttributeFinder(const ResTable::bag_entry * start,const ResTable::bag_entry * end)1054     BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1055         : BackTrackingAttributeFinder(start, end) {}
1056 
getAttribute(const ResTable::bag_entry * entry) const1057     inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1058         return entry->map.name.ident;
1059     }
1060 };
1061 
android_content_AssetManager_resolveAttrs(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jintArray inValues,jintArray attrs,jintArray outValues,jintArray outIndices)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 
android_content_AssetManager_applyStyle(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)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 
android_content_AssetManager_retrieveAttributes(JNIEnv * env,jobject clazz,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)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 
android_content_AssetManager_getArraySize(JNIEnv * env,jobject clazz,jint id)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 
android_content_AssetManager_retrieveArray(JNIEnv * env,jobject clazz,jint id,jintArray outValues)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 
android_content_AssetManager_openXmlAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName)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 
android_content_AssetManager_getArrayStringInfo(JNIEnv * env,jobject clazz,jint arrayResId)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 
android_content_AssetManager_getArrayStringResource(JNIEnv * env,jobject clazz,jint arrayResId)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 
android_content_AssetManager_getArrayIntResource(JNIEnv * env,jobject clazz,jint arrayResId)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 
android_content_AssetManager_getStyleAttributes(JNIEnv * env,jobject clazz,jint styleId)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 
android_content_AssetManager_init(JNIEnv * env,jobject clazz,jboolean isSystem)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 
android_content_AssetManager_destroy(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_getGlobalAssetCount(JNIEnv * env,jobject clazz)2030 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
2031 {
2032     return Asset::getGlobalCount();
2033 }
2034 
android_content_AssetManager_getAssetAllocations(JNIEnv * env,jobject clazz)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 
android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv * env,jobject clazz)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 
register_android_content_AssetManager(JNIEnv * env)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
2211