• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define DEBUG_STYLES(x) //x
21 #define THROW_ON_BAD_ID 0
22 
23 #include <android_runtime/android_util_AssetManager.h>
24 
25 #include "jni.h"
26 #include "JNIHelp.h"
27 #include "ScopedStringChars.h"
28 #include "ScopedUtfChars.h"
29 #include "android_util_Binder.h"
30 #include <utils/misc.h>
31 #include <android_runtime/AndroidRuntime.h>
32 #include <utils/Log.h>
33 
34 #include <androidfw/Asset.h>
35 #include <androidfw/AssetManager.h>
36 #include <androidfw/AttributeFinder.h>
37 #include <androidfw/ResourceTypes.h>
38 
39 #include <private/android_filesystem_config.h> // for AID_SYSTEM
40 
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 
45 #include <linux/capability.h>
46 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
47 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
48 
49 
50 namespace android {
51 
52 // ----------------------------------------------------------------------------
53 
54 static struct typedvalue_offsets_t
55 {
56     jfieldID mType;
57     jfieldID mData;
58     jfieldID mString;
59     jfieldID mAssetCookie;
60     jfieldID mResourceId;
61     jfieldID mChangingConfigurations;
62     jfieldID mDensity;
63 } gTypedValueOffsets;
64 
65 static struct assetfiledescriptor_offsets_t
66 {
67     jfieldID mFd;
68     jfieldID mStartOffset;
69     jfieldID mLength;
70 } gAssetFileDescriptorOffsets;
71 
72 static struct assetmanager_offsets_t
73 {
74     jfieldID mObject;
75 } gAssetManagerOffsets;
76 
77 static struct sparsearray_offsets_t
78 {
79     jclass classObject;
80     jmethodID constructor;
81     jmethodID put;
82 } gSparseArrayOffsets;
83 
84 jclass g_stringClass = NULL;
85 
86 // ----------------------------------------------------------------------------
87 
88 enum {
89     STYLE_NUM_ENTRIES = 6,
90     STYLE_TYPE = 0,
91     STYLE_DATA = 1,
92     STYLE_ASSET_COOKIE = 2,
93     STYLE_RESOURCE_ID = 3,
94     STYLE_CHANGING_CONFIGURATIONS = 4,
95     STYLE_DENSITY = 5
96 };
97 
98 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
99                       const Res_value& value, uint32_t ref, ssize_t block,
100                       uint32_t typeSpecFlags, ResTable_config* config = NULL);
101 
copyValue(JNIEnv * env,jobject outValue,const ResTable * table,const Res_value & value,uint32_t ref,ssize_t block,uint32_t typeSpecFlags,ResTable_config * config)102 jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
103                const Res_value& value, uint32_t ref, ssize_t block,
104                uint32_t typeSpecFlags, ResTable_config* config)
105 {
106     env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
107     env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
108                      static_cast<jint>(table->getTableCookie(block)));
109     env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
110     env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
111     env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
112     env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
113             typeSpecFlags);
114     if (config != NULL) {
115         env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
116     }
117     return block;
118 }
119 
120 // This is called by zygote (running as user root) as part of preloadResources.
verifySystemIdmaps()121 static void verifySystemIdmaps()
122 {
123     pid_t pid;
124     char system_id[10];
125 
126     snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
127 
128     switch (pid = fork()) {
129         case -1:
130             ALOGE("failed to fork for idmap: %s", strerror(errno));
131             break;
132         case 0: // child
133             {
134                 struct __user_cap_header_struct capheader;
135                 struct __user_cap_data_struct capdata;
136 
137                 memset(&capheader, 0, sizeof(capheader));
138                 memset(&capdata, 0, sizeof(capdata));
139 
140                 capheader.version = _LINUX_CAPABILITY_VERSION;
141                 capheader.pid = 0;
142 
143                 if (capget(&capheader, &capdata) != 0) {
144                     ALOGE("capget: %s\n", strerror(errno));
145                     exit(1);
146                 }
147 
148                 capdata.effective = capdata.permitted;
149                 if (capset(&capheader, &capdata) != 0) {
150                     ALOGE("capset: %s\n", strerror(errno));
151                     exit(1);
152                 }
153 
154                 if (setgid(AID_SYSTEM) != 0) {
155                     ALOGE("setgid: %s\n", strerror(errno));
156                     exit(1);
157                 }
158 
159                 if (setuid(AID_SYSTEM) != 0) {
160                     ALOGE("setuid: %s\n", strerror(errno));
161                     exit(1);
162                 }
163 
164                 execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan",
165                         AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME,
166                         AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL);
167                 ALOGE("failed to execl for idmap: %s", strerror(errno));
168                 exit(1); // should never get here
169             }
170             break;
171         default: // parent
172             waitpid(pid, NULL, 0);
173             break;
174     }
175 }
176 
177 // ----------------------------------------------------------------------------
178 
179 // this guy is exported to other jni routines
assetManagerForJavaObject(JNIEnv * env,jobject obj)180 AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
181 {
182     jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
183     AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
184     if (am != NULL) {
185         return am;
186     }
187     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
188     return NULL;
189 }
190 
android_content_AssetManager_openAsset(JNIEnv * env,jobject clazz,jstring fileName,jint mode)191 static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
192                                                 jstring fileName, jint mode)
193 {
194     AssetManager* am = assetManagerForJavaObject(env, clazz);
195     if (am == NULL) {
196         return 0;
197     }
198 
199     ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
200 
201     ScopedUtfChars fileName8(env, fileName);
202     if (fileName8.c_str() == NULL) {
203         jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
204         return -1;
205     }
206 
207     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
208         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
209         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
210         return -1;
211     }
212 
213     Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
214 
215     if (a == NULL) {
216         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
217         return -1;
218     }
219 
220     //printf("Created Asset Stream: %p\n", a);
221 
222     return reinterpret_cast<jlong>(a);
223 }
224 
returnParcelFileDescriptor(JNIEnv * env,Asset * a,jlongArray outOffsets)225 static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
226 {
227     off64_t startOffset, length;
228     int fd = a->openFileDescriptor(&startOffset, &length);
229     delete a;
230 
231     if (fd < 0) {
232         jniThrowException(env, "java/io/FileNotFoundException",
233                 "This file can not be opened as a file descriptor; it is probably compressed");
234         return NULL;
235     }
236 
237     jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
238     if (offsets == NULL) {
239         close(fd);
240         return NULL;
241     }
242 
243     offsets[0] = startOffset;
244     offsets[1] = length;
245 
246     env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
247 
248     jobject fileDesc = jniCreateFileDescriptor(env, fd);
249     if (fileDesc == NULL) {
250         close(fd);
251         return NULL;
252     }
253 
254     return newParcelFileDescriptor(env, fileDesc);
255 }
256 
android_content_AssetManager_openAssetFd(JNIEnv * env,jobject clazz,jstring fileName,jlongArray outOffsets)257 static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
258                                                 jstring fileName, jlongArray outOffsets)
259 {
260     AssetManager* am = assetManagerForJavaObject(env, clazz);
261     if (am == NULL) {
262         return NULL;
263     }
264 
265     ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
266 
267     ScopedUtfChars fileName8(env, fileName);
268     if (fileName8.c_str() == NULL) {
269         return NULL;
270     }
271 
272     Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
273 
274     if (a == NULL) {
275         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
276         return NULL;
277     }
278 
279     //printf("Created Asset Stream: %p\n", a);
280 
281     return returnParcelFileDescriptor(env, a, outOffsets);
282 }
283 
android_content_AssetManager_openNonAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jint mode)284 static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
285                                                          jint cookie,
286                                                          jstring fileName,
287                                                          jint mode)
288 {
289     AssetManager* am = assetManagerForJavaObject(env, clazz);
290     if (am == NULL) {
291         return 0;
292     }
293 
294     ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
295 
296     ScopedUtfChars fileName8(env, fileName);
297     if (fileName8.c_str() == NULL) {
298         return -1;
299     }
300 
301     if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
302         && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
303         jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
304         return -1;
305     }
306 
307     Asset* a = cookie
308         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
309                 (Asset::AccessMode)mode)
310         : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
311 
312     if (a == NULL) {
313         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
314         return -1;
315     }
316 
317     //printf("Created Asset Stream: %p\n", a);
318 
319     return reinterpret_cast<jlong>(a);
320 }
321 
android_content_AssetManager_openNonAssetFdNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName,jlongArray outOffsets)322 static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
323                                                          jint cookie,
324                                                          jstring fileName,
325                                                          jlongArray outOffsets)
326 {
327     AssetManager* am = assetManagerForJavaObject(env, clazz);
328     if (am == NULL) {
329         return NULL;
330     }
331 
332     ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
333 
334     ScopedUtfChars fileName8(env, fileName);
335     if (fileName8.c_str() == NULL) {
336         return NULL;
337     }
338 
339     Asset* a = cookie
340         ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
341         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
342 
343     if (a == NULL) {
344         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
345         return NULL;
346     }
347 
348     //printf("Created Asset Stream: %p\n", a);
349 
350     return returnParcelFileDescriptor(env, a, outOffsets);
351 }
352 
android_content_AssetManager_list(JNIEnv * env,jobject clazz,jstring fileName)353 static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
354                                                    jstring fileName)
355 {
356     AssetManager* am = assetManagerForJavaObject(env, clazz);
357     if (am == NULL) {
358         return NULL;
359     }
360 
361     ScopedUtfChars fileName8(env, fileName);
362     if (fileName8.c_str() == NULL) {
363         return NULL;
364     }
365 
366     AssetDir* dir = am->openDir(fileName8.c_str());
367 
368     if (dir == NULL) {
369         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
370         return NULL;
371     }
372 
373     size_t N = dir->getFileCount();
374 
375     jobjectArray array = env->NewObjectArray(dir->getFileCount(),
376                                                 g_stringClass, NULL);
377     if (array == NULL) {
378         delete dir;
379         return NULL;
380     }
381 
382     for (size_t i=0; i<N; i++) {
383         const String8& name = dir->getFileName(i);
384         jstring str = env->NewStringUTF(name.string());
385         if (str == NULL) {
386             delete dir;
387             return NULL;
388         }
389         env->SetObjectArrayElement(array, i, str);
390         env->DeleteLocalRef(str);
391     }
392 
393     delete dir;
394 
395     return array;
396 }
397 
android_content_AssetManager_destroyAsset(JNIEnv * env,jobject clazz,jlong assetHandle)398 static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
399                                                       jlong assetHandle)
400 {
401     Asset* a = reinterpret_cast<Asset*>(assetHandle);
402 
403     //printf("Destroying Asset Stream: %p\n", a);
404 
405     if (a == NULL) {
406         jniThrowNullPointerException(env, "asset");
407         return;
408     }
409 
410     delete a;
411 }
412 
android_content_AssetManager_readAssetChar(JNIEnv * env,jobject clazz,jlong assetHandle)413 static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
414                                                        jlong assetHandle)
415 {
416     Asset* a = reinterpret_cast<Asset*>(assetHandle);
417 
418     if (a == NULL) {
419         jniThrowNullPointerException(env, "asset");
420         return -1;
421     }
422 
423     uint8_t b;
424     ssize_t res = a->read(&b, 1);
425     return res == 1 ? b : -1;
426 }
427 
android_content_AssetManager_readAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jbyteArray bArray,jint off,jint len)428 static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
429                                                 jlong assetHandle, jbyteArray bArray,
430                                                 jint off, jint len)
431 {
432     Asset* a = reinterpret_cast<Asset*>(assetHandle);
433 
434     if (a == NULL || bArray == NULL) {
435         jniThrowNullPointerException(env, "asset");
436         return -1;
437     }
438 
439     if (len == 0) {
440         return 0;
441     }
442 
443     jsize bLen = env->GetArrayLength(bArray);
444     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
445         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
446         return -1;
447     }
448 
449     jbyte* b = env->GetByteArrayElements(bArray, NULL);
450     ssize_t res = a->read(b+off, len);
451     env->ReleaseByteArrayElements(bArray, b, 0);
452 
453     if (res > 0) return static_cast<jint>(res);
454 
455     if (res < 0) {
456         jniThrowException(env, "java/io/IOException", "");
457     }
458     return -1;
459 }
460 
android_content_AssetManager_seekAsset(JNIEnv * env,jobject clazz,jlong assetHandle,jlong offset,jint whence)461 static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
462                                                  jlong assetHandle,
463                                                  jlong offset, jint whence)
464 {
465     Asset* a = reinterpret_cast<Asset*>(assetHandle);
466 
467     if (a == NULL) {
468         jniThrowNullPointerException(env, "asset");
469         return -1;
470     }
471 
472     return a->seek(
473         offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
474 }
475 
android_content_AssetManager_getAssetLength(JNIEnv * env,jobject clazz,jlong assetHandle)476 static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
477                                                       jlong assetHandle)
478 {
479     Asset* a = reinterpret_cast<Asset*>(assetHandle);
480 
481     if (a == NULL) {
482         jniThrowNullPointerException(env, "asset");
483         return -1;
484     }
485 
486     return a->getLength();
487 }
488 
android_content_AssetManager_getAssetRemainingLength(JNIEnv * env,jobject clazz,jlong assetHandle)489 static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
490                                                                jlong assetHandle)
491 {
492     Asset* a = reinterpret_cast<Asset*>(assetHandle);
493 
494     if (a == NULL) {
495         jniThrowNullPointerException(env, "asset");
496         return -1;
497     }
498 
499     return a->getRemainingLength();
500 }
501 
android_content_AssetManager_addAssetPath(JNIEnv * env,jobject clazz,jstring path)502 static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
503                                                        jstring path)
504 {
505     ScopedUtfChars path8(env, path);
506     if (path8.c_str() == NULL) {
507         return 0;
508     }
509 
510     AssetManager* am = assetManagerForJavaObject(env, clazz);
511     if (am == NULL) {
512         return 0;
513     }
514 
515     int32_t cookie;
516     bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
517 
518     return (res) ? static_cast<jint>(cookie) : 0;
519 }
520 
android_content_AssetManager_addOverlayPath(JNIEnv * env,jobject clazz,jstring idmapPath)521 static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
522                                                      jstring idmapPath)
523 {
524     ScopedUtfChars idmapPath8(env, idmapPath);
525     if (idmapPath8.c_str() == NULL) {
526         return 0;
527     }
528 
529     AssetManager* am = assetManagerForJavaObject(env, clazz);
530     if (am == NULL) {
531         return 0;
532     }
533 
534     int32_t cookie;
535     bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
536 
537     return (res) ? (jint)cookie : 0;
538 }
539 
android_content_AssetManager_isUpToDate(JNIEnv * env,jobject clazz)540 static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
541 {
542     AssetManager* am = assetManagerForJavaObject(env, clazz);
543     if (am == NULL) {
544         return JNI_TRUE;
545     }
546     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
547 }
548 
android_content_AssetManager_setLocale(JNIEnv * env,jobject clazz,jstring locale)549 static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
550                                                 jstring locale)
551 {
552     ScopedUtfChars locale8(env, locale);
553     if (locale8.c_str() == NULL) {
554         return;
555     }
556 
557     AssetManager* am = assetManagerForJavaObject(env, clazz);
558     if (am == NULL) {
559         return;
560     }
561 
562     am->setLocale(locale8.c_str());
563 }
564 
android_content_AssetManager_getLocales(JNIEnv * env,jobject clazz)565 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
566 {
567     Vector<String8> locales;
568 
569     AssetManager* am = assetManagerForJavaObject(env, clazz);
570     if (am == NULL) {
571         return NULL;
572     }
573 
574     am->getLocales(&locales);
575 
576     const int N = locales.size();
577 
578     jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
579     if (result == NULL) {
580         return NULL;
581     }
582 
583     for (int i=0; i<N; i++) {
584         jstring str = env->NewStringUTF(locales[i].string());
585         if (str == NULL) {
586             return NULL;
587         }
588         env->SetObjectArrayElement(result, i, str);
589         env->DeleteLocalRef(str);
590     }
591 
592     return result;
593 }
594 
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)595 static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
596                                                           jint mcc, jint mnc,
597                                                           jstring locale, jint orientation,
598                                                           jint touchscreen, jint density,
599                                                           jint keyboard, jint keyboardHidden,
600                                                           jint navigation,
601                                                           jint screenWidth, jint screenHeight,
602                                                           jint smallestScreenWidthDp,
603                                                           jint screenWidthDp, jint screenHeightDp,
604                                                           jint screenLayout, jint uiMode,
605                                                           jint sdkVersion)
606 {
607     AssetManager* am = assetManagerForJavaObject(env, clazz);
608     if (am == NULL) {
609         return;
610     }
611 
612     ResTable_config config;
613     memset(&config, 0, sizeof(config));
614 
615     const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
616 
617     config.mcc = (uint16_t)mcc;
618     config.mnc = (uint16_t)mnc;
619     config.orientation = (uint8_t)orientation;
620     config.touchscreen = (uint8_t)touchscreen;
621     config.density = (uint16_t)density;
622     config.keyboard = (uint8_t)keyboard;
623     config.inputFlags = (uint8_t)keyboardHidden;
624     config.navigation = (uint8_t)navigation;
625     config.screenWidth = (uint16_t)screenWidth;
626     config.screenHeight = (uint16_t)screenHeight;
627     config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
628     config.screenWidthDp = (uint16_t)screenWidthDp;
629     config.screenHeightDp = (uint16_t)screenHeightDp;
630     config.screenLayout = (uint8_t)screenLayout;
631     config.uiMode = (uint8_t)uiMode;
632     config.sdkVersion = (uint16_t)sdkVersion;
633     config.minorVersion = 0;
634     am->setConfiguration(config, locale8);
635 
636     if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
637 }
638 
android_content_AssetManager_getResourceIdentifier(JNIEnv * env,jobject clazz,jstring name,jstring defType,jstring defPackage)639 static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
640                                                             jstring name,
641                                                             jstring defType,
642                                                             jstring defPackage)
643 {
644     ScopedStringChars name16(env, name);
645     if (name16.get() == NULL) {
646         return 0;
647     }
648 
649     AssetManager* am = assetManagerForJavaObject(env, clazz);
650     if (am == NULL) {
651         return 0;
652     }
653 
654     const char16_t* defType16 = defType
655         ? env->GetStringChars(defType, NULL) : NULL;
656     jsize defTypeLen = defType
657         ? env->GetStringLength(defType) : 0;
658     const char16_t* defPackage16 = defPackage
659         ? env->GetStringChars(defPackage, NULL) : NULL;
660     jsize defPackageLen = defPackage
661         ? env->GetStringLength(defPackage) : 0;
662 
663     jint ident = am->getResources().identifierForName(
664         name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
665 
666     if (defPackage16) {
667         env->ReleaseStringChars(defPackage, defPackage16);
668     }
669     if (defType16) {
670         env->ReleaseStringChars(defType, defType16);
671     }
672 
673     return ident;
674 }
675 
android_content_AssetManager_getResourceName(JNIEnv * env,jobject clazz,jint resid)676 static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
677                                                             jint resid)
678 {
679     AssetManager* am = assetManagerForJavaObject(env, clazz);
680     if (am == NULL) {
681         return NULL;
682     }
683 
684     ResTable::resource_name name;
685     if (!am->getResources().getResourceName(resid, true, &name)) {
686         return NULL;
687     }
688 
689     String16 str;
690     if (name.package != NULL) {
691         str.setTo(name.package, name.packageLen);
692     }
693     if (name.type8 != NULL || name.type != NULL) {
694         if (str.size() > 0) {
695             char16_t div = ':';
696             str.append(&div, 1);
697         }
698         if (name.type8 != NULL) {
699             str.append(String16(name.type8, name.typeLen));
700         } else {
701             str.append(name.type, name.typeLen);
702         }
703     }
704     if (name.name8 != NULL || name.name != NULL) {
705         if (str.size() > 0) {
706             char16_t div = '/';
707             str.append(&div, 1);
708         }
709         if (name.name8 != NULL) {
710             str.append(String16(name.name8, name.nameLen));
711         } else {
712             str.append(name.name, name.nameLen);
713         }
714     }
715 
716     return env->NewString((const jchar*)str.string(), str.size());
717 }
718 
android_content_AssetManager_getResourcePackageName(JNIEnv * env,jobject clazz,jint resid)719 static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
720                                                                    jint resid)
721 {
722     AssetManager* am = assetManagerForJavaObject(env, clazz);
723     if (am == NULL) {
724         return NULL;
725     }
726 
727     ResTable::resource_name name;
728     if (!am->getResources().getResourceName(resid, true, &name)) {
729         return NULL;
730     }
731 
732     if (name.package != NULL) {
733         return env->NewString((const jchar*)name.package, name.packageLen);
734     }
735 
736     return NULL;
737 }
738 
android_content_AssetManager_getResourceTypeName(JNIEnv * env,jobject clazz,jint resid)739 static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
740                                                                 jint resid)
741 {
742     AssetManager* am = assetManagerForJavaObject(env, clazz);
743     if (am == NULL) {
744         return NULL;
745     }
746 
747     ResTable::resource_name name;
748     if (!am->getResources().getResourceName(resid, true, &name)) {
749         return NULL;
750     }
751 
752     if (name.type8 != NULL) {
753         return env->NewStringUTF(name.type8);
754     }
755 
756     if (name.type != NULL) {
757         return env->NewString((const jchar*)name.type, name.typeLen);
758     }
759 
760     return NULL;
761 }
762 
android_content_AssetManager_getResourceEntryName(JNIEnv * env,jobject clazz,jint resid)763 static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
764                                                                  jint resid)
765 {
766     AssetManager* am = assetManagerForJavaObject(env, clazz);
767     if (am == NULL) {
768         return NULL;
769     }
770 
771     ResTable::resource_name name;
772     if (!am->getResources().getResourceName(resid, true, &name)) {
773         return NULL;
774     }
775 
776     if (name.name8 != NULL) {
777         return env->NewStringUTF(name.name8);
778     }
779 
780     if (name.name != NULL) {
781         return env->NewString((const jchar*)name.name, name.nameLen);
782     }
783 
784     return NULL;
785 }
786 
android_content_AssetManager_loadResourceValue(JNIEnv * env,jobject clazz,jint ident,jshort density,jobject outValue,jboolean resolve)787 static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
788                                                            jint ident,
789                                                            jshort density,
790                                                            jobject outValue,
791                                                            jboolean resolve)
792 {
793     if (outValue == NULL) {
794          jniThrowNullPointerException(env, "outValue");
795          return 0;
796     }
797     AssetManager* am = assetManagerForJavaObject(env, clazz);
798     if (am == NULL) {
799         return 0;
800     }
801     const ResTable& res(am->getResources());
802 
803     Res_value value;
804     ResTable_config config;
805     uint32_t typeSpecFlags;
806     ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
807 #if THROW_ON_BAD_ID
808     if (block == BAD_INDEX) {
809         jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
810         return 0;
811     }
812 #endif
813     uint32_t ref = ident;
814     if (resolve) {
815         block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
816 #if THROW_ON_BAD_ID
817         if (block == BAD_INDEX) {
818             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
819             return 0;
820         }
821 #endif
822     }
823     if (block >= 0) {
824         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
825     }
826 
827     return static_cast<jint>(block);
828 }
829 
android_content_AssetManager_loadResourceBagValue(JNIEnv * env,jobject clazz,jint ident,jint bagEntryId,jobject outValue,jboolean resolve)830 static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
831                                                            jint ident, jint bagEntryId,
832                                                            jobject outValue, jboolean resolve)
833 {
834     AssetManager* am = assetManagerForJavaObject(env, clazz);
835     if (am == NULL) {
836         return 0;
837     }
838     const ResTable& res(am->getResources());
839 
840     // Now lock down the resource object and start pulling stuff from it.
841     res.lock();
842 
843     ssize_t block = -1;
844     Res_value value;
845 
846     const ResTable::bag_entry* entry = NULL;
847     uint32_t typeSpecFlags;
848     ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
849 
850     for (ssize_t i=0; i<entryCount; i++) {
851         if (((uint32_t)bagEntryId) == entry->map.name.ident) {
852             block = entry->stringBlock;
853             value = entry->map.value;
854         }
855         entry++;
856     }
857 
858     res.unlock();
859 
860     if (block < 0) {
861         return static_cast<jint>(block);
862     }
863 
864     uint32_t ref = ident;
865     if (resolve) {
866         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
867 #if THROW_ON_BAD_ID
868         if (block == BAD_INDEX) {
869             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
870             return 0;
871         }
872 #endif
873     }
874     if (block >= 0) {
875         return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
876     }
877 
878     return static_cast<jint>(block);
879 }
880 
android_content_AssetManager_getStringBlockCount(JNIEnv * env,jobject clazz)881 static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
882 {
883     AssetManager* am = assetManagerForJavaObject(env, clazz);
884     if (am == NULL) {
885         return 0;
886     }
887     return am->getResources().getTableCount();
888 }
889 
android_content_AssetManager_getNativeStringBlock(JNIEnv * env,jobject clazz,jint block)890 static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
891                                                            jint block)
892 {
893     AssetManager* am = assetManagerForJavaObject(env, clazz);
894     if (am == NULL) {
895         return 0;
896     }
897     return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
898 }
899 
android_content_AssetManager_getCookieName(JNIEnv * env,jobject clazz,jint cookie)900 static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
901                                                        jint cookie)
902 {
903     AssetManager* am = assetManagerForJavaObject(env, clazz);
904     if (am == NULL) {
905         return NULL;
906     }
907     String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
908     if (name.length() == 0) {
909         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
910         return NULL;
911     }
912     jstring str = env->NewStringUTF(name.string());
913     return str;
914 }
915 
android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv * env,jobject clazz)916 static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
917 {
918     AssetManager* am = assetManagerForJavaObject(env, clazz);
919     if (am == NULL) {
920         return 0;
921     }
922 
923     const ResTable& res = am->getResources();
924 
925     jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
926             gSparseArrayOffsets.constructor);
927     const size_t N = res.getBasePackageCount();
928     for (size_t i = 0; i < N; i++) {
929         const String16 name = res.getBasePackageName(i);
930         env->CallVoidMethod(sparseArray, gSparseArrayOffsets.put, (jint) res.getBasePackageId(i),
931                 env->NewString(name, name.size()));
932     }
933     return sparseArray;
934 }
935 
android_content_AssetManager_newTheme(JNIEnv * env,jobject clazz)936 static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
937 {
938     AssetManager* am = assetManagerForJavaObject(env, clazz);
939     if (am == NULL) {
940         return 0;
941     }
942     return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
943 }
944 
android_content_AssetManager_deleteTheme(JNIEnv * env,jobject clazz,jlong themeHandle)945 static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
946                                                      jlong themeHandle)
947 {
948     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
949     delete theme;
950 }
951 
android_content_AssetManager_applyThemeStyle(JNIEnv * env,jobject clazz,jlong themeHandle,jint styleRes,jboolean force)952 static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
953                                                          jlong themeHandle,
954                                                          jint styleRes,
955                                                          jboolean force)
956 {
957     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
958     theme->applyStyle(styleRes, force ? true : false);
959 }
960 
android_content_AssetManager_copyTheme(JNIEnv * env,jobject clazz,jlong destHandle,jlong srcHandle)961 static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
962                                                    jlong destHandle, jlong srcHandle)
963 {
964     ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
965     ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
966     dest->setTo(*src);
967 }
968 
android_content_AssetManager_loadThemeAttributeValue(JNIEnv * env,jobject clazz,jlong themeHandle,jint ident,jobject outValue,jboolean resolve)969 static jint android_content_AssetManager_loadThemeAttributeValue(
970     JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
971 {
972     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
973     const ResTable& res(theme->getResTable());
974 
975     Res_value value;
976     // XXX value could be different in different configs!
977     uint32_t typeSpecFlags = 0;
978     ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
979     uint32_t ref = 0;
980     if (resolve) {
981         block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
982 #if THROW_ON_BAD_ID
983         if (block == BAD_INDEX) {
984             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
985             return 0;
986         }
987 #endif
988     }
989     return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
990 }
991 
android_content_AssetManager_dumpTheme(JNIEnv * env,jobject clazz,jlong themeHandle,jint pri,jstring tag,jstring prefix)992 static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
993                                                    jlong themeHandle, jint pri,
994                                                    jstring tag, jstring prefix)
995 {
996     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
997     const ResTable& res(theme->getResTable());
998 
999     // XXX Need to use params.
1000     theme->dumpToLog();
1001 }
1002 
1003 class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
1004 public:
XmlAttributeFinder(const ResXMLParser * parser)1005     XmlAttributeFinder(const ResXMLParser* parser)
1006         : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
1007         , mParser(parser) {}
1008 
getAttribute(jsize index) const1009     inline uint32_t getAttribute(jsize index) const {
1010         return mParser->getAttributeNameResID(index);
1011     }
1012 
1013 private:
1014     const ResXMLParser* mParser;
1015 };
1016 
1017 class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
1018 public:
BagAttributeFinder(const ResTable::bag_entry * start,const ResTable::bag_entry * end)1019     BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
1020         : BackTrackingAttributeFinder(start, end) {}
1021 
getAttribute(const ResTable::bag_entry * entry) const1022     inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
1023         return entry->map.name.ident;
1024     }
1025 };
1026 
android_content_AssetManager_resolveAttrs(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jintArray inValues,jintArray attrs,jintArray outValues,jintArray outIndices)1027 static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
1028                                                           jlong themeToken,
1029                                                           jint defStyleAttr,
1030                                                           jint defStyleRes,
1031                                                           jintArray inValues,
1032                                                           jintArray attrs,
1033                                                           jintArray outValues,
1034                                                           jintArray outIndices)
1035 {
1036     if (themeToken == 0) {
1037         jniThrowNullPointerException(env, "theme token");
1038         return JNI_FALSE;
1039     }
1040     if (attrs == NULL) {
1041         jniThrowNullPointerException(env, "attrs");
1042         return JNI_FALSE;
1043     }
1044     if (outValues == NULL) {
1045         jniThrowNullPointerException(env, "out values");
1046         return JNI_FALSE;
1047     }
1048 
1049     DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x",
1050         themeToken, defStyleAttr, defStyleRes));
1051 
1052     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1053     const ResTable& res = theme->getResTable();
1054     ResTable_config config;
1055     Res_value value;
1056 
1057     const jsize NI = env->GetArrayLength(attrs);
1058     const jsize NV = env->GetArrayLength(outValues);
1059     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1060         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1061         return JNI_FALSE;
1062     }
1063 
1064     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1065     if (src == NULL) {
1066         return JNI_FALSE;
1067     }
1068 
1069     jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
1070     const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
1071 
1072     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1073     jint* dest = baseDest;
1074     if (dest == NULL) {
1075         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1076         return JNI_FALSE;
1077     }
1078 
1079     jint* indices = NULL;
1080     int indicesIdx = 0;
1081     if (outIndices != NULL) {
1082         if (env->GetArrayLength(outIndices) > NI) {
1083             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1084         }
1085     }
1086 
1087     // Load default style from attribute, if specified...
1088     uint32_t defStyleBagTypeSetFlags = 0;
1089     if (defStyleAttr != 0) {
1090         Res_value value;
1091         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1092             if (value.dataType == Res_value::TYPE_REFERENCE) {
1093                 defStyleRes = value.data;
1094             }
1095         }
1096     }
1097 
1098     // Now lock down the resource object and start pulling stuff from it.
1099     res.lock();
1100 
1101     // Retrieve the default style bag, if requested.
1102     const ResTable::bag_entry* defStyleStart = NULL;
1103     uint32_t defStyleTypeSetFlags = 0;
1104     ssize_t bagOff = defStyleRes != 0
1105             ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
1106     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1107     const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
1108     BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
1109 
1110     // Now iterate through all of the attributes that the client has requested,
1111     // filling in each with whatever data we can find.
1112     ssize_t block = 0;
1113     uint32_t typeSetFlags;
1114     for (jsize ii=0; ii<NI; ii++) {
1115         const uint32_t curIdent = (uint32_t)src[ii];
1116 
1117         DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1118 
1119         // Try to find a value for this attribute...  we prioritize values
1120         // coming from, first XML attributes, then XML style, then default
1121         // style, and finally the theme.
1122         value.dataType = Res_value::TYPE_NULL;
1123         value.data = Res_value::DATA_NULL_UNDEFINED;
1124         typeSetFlags = 0;
1125         config.density = 0;
1126 
1127         // Retrieve the current input value if available.
1128         if (NSV > 0 && srcValues[ii] != 0) {
1129             block = -1;
1130             value.dataType = Res_value::TYPE_ATTRIBUTE;
1131             value.data = srcValues[ii];
1132             DEBUG_STYLES(ALOGI("-> From values: type=0x%x, data=0x%08x",
1133                     value.dataType, value.data));
1134         }
1135 
1136         if (value.dataType == Res_value::TYPE_NULL) {
1137             const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
1138             if (defStyleEntry != defStyleEnd) {
1139                 block = defStyleEntry->stringBlock;
1140                 typeSetFlags = defStyleTypeSetFlags;
1141                 value = defStyleEntry->map.value;
1142                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
1143                         value.dataType, value.data));
1144             }
1145         }
1146 
1147         uint32_t resid = 0;
1148         if (value.dataType != Res_value::TYPE_NULL) {
1149             // Take care of resolving the found resource to its final value.
1150             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1151                     &resid, &typeSetFlags, &config);
1152             if (newBlock >= 0) block = newBlock;
1153             DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1154                     value.dataType, value.data));
1155         } else {
1156             // If we still don't have a value for this attribute, try to find
1157             // it in the theme!
1158             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1159             if (newBlock >= 0) {
1160                 DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
1161                         value.dataType, value.data));
1162                 newBlock = res.resolveReference(&value, block, &resid,
1163                         &typeSetFlags, &config);
1164 #if THROW_ON_BAD_ID
1165                 if (newBlock == BAD_INDEX) {
1166                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1167                     return JNI_FALSE;
1168                 }
1169 #endif
1170                 if (newBlock >= 0) block = newBlock;
1171                 DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1172                         value.dataType, value.data));
1173             }
1174         }
1175 
1176         // Deal with the special @null value -- it turns back to TYPE_NULL.
1177         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1178             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
1179             value.dataType = Res_value::TYPE_NULL;
1180             value.data = Res_value::DATA_NULL_UNDEFINED;
1181             block = -1;
1182         }
1183 
1184         DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1185                 curIdent, value.dataType, value.data));
1186 
1187         // Write the final value back to Java.
1188         dest[STYLE_TYPE] = value.dataType;
1189         dest[STYLE_DATA] = value.data;
1190         dest[STYLE_ASSET_COOKIE] =
1191             block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1192         dest[STYLE_RESOURCE_ID] = resid;
1193         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1194         dest[STYLE_DENSITY] = config.density;
1195 
1196         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1197             indicesIdx++;
1198             indices[indicesIdx] = ii;
1199         }
1200 
1201         dest += STYLE_NUM_ENTRIES;
1202     }
1203 
1204     res.unlock();
1205 
1206     if (indices != NULL) {
1207         indices[0] = indicesIdx;
1208         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1209     }
1210     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1211     env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
1212     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1213 
1214     return JNI_TRUE;
1215 }
1216 
android_content_AssetManager_applyStyle(JNIEnv * env,jobject clazz,jlong themeToken,jint defStyleAttr,jint defStyleRes,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)1217 static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
1218                                                         jlong themeToken,
1219                                                         jint defStyleAttr,
1220                                                         jint defStyleRes,
1221                                                         jlong xmlParserToken,
1222                                                         jintArray attrs,
1223                                                         jintArray outValues,
1224                                                         jintArray outIndices)
1225 {
1226     if (themeToken == 0) {
1227         jniThrowNullPointerException(env, "theme token");
1228         return JNI_FALSE;
1229     }
1230     if (attrs == NULL) {
1231         jniThrowNullPointerException(env, "attrs");
1232         return JNI_FALSE;
1233     }
1234     if (outValues == NULL) {
1235         jniThrowNullPointerException(env, "out values");
1236         return JNI_FALSE;
1237     }
1238 
1239     DEBUG_STYLES(ALOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
1240         themeToken, defStyleAttr, defStyleRes, xmlParserToken));
1241 
1242     ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
1243     const ResTable& res = theme->getResTable();
1244     ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
1245     ResTable_config config;
1246     Res_value value;
1247 
1248     const jsize NI = env->GetArrayLength(attrs);
1249     const jsize NV = env->GetArrayLength(outValues);
1250     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1251         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1252         return JNI_FALSE;
1253     }
1254 
1255     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1256     if (src == NULL) {
1257         return JNI_FALSE;
1258     }
1259 
1260     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1261     jint* dest = baseDest;
1262     if (dest == NULL) {
1263         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1264         return JNI_FALSE;
1265     }
1266 
1267     jint* indices = NULL;
1268     int indicesIdx = 0;
1269     if (outIndices != NULL) {
1270         if (env->GetArrayLength(outIndices) > NI) {
1271             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1272         }
1273     }
1274 
1275     // Load default style from attribute, if specified...
1276     uint32_t defStyleBagTypeSetFlags = 0;
1277     if (defStyleAttr != 0) {
1278         Res_value value;
1279         if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
1280             if (value.dataType == Res_value::TYPE_REFERENCE) {
1281                 defStyleRes = value.data;
1282             }
1283         }
1284     }
1285 
1286     // Retrieve the style class associated with the current XML tag.
1287     int style = 0;
1288     uint32_t styleBagTypeSetFlags = 0;
1289     if (xmlParser != NULL) {
1290         ssize_t idx = xmlParser->indexOfStyle();
1291         if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
1292             if (value.dataType == value.TYPE_ATTRIBUTE) {
1293                 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
1294                     value.dataType = Res_value::TYPE_NULL;
1295                 }
1296             }
1297             if (value.dataType == value.TYPE_REFERENCE) {
1298                 style = value.data;
1299             }
1300         }
1301     }
1302 
1303     // Now lock down the resource object and start pulling stuff from it.
1304     res.lock();
1305 
1306     // Retrieve the default style bag, if requested.
1307     const ResTable::bag_entry* defStyleAttrStart = NULL;
1308     uint32_t defStyleTypeSetFlags = 0;
1309     ssize_t bagOff = defStyleRes != 0
1310             ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
1311     defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
1312     const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
1313     BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
1314 
1315     // Retrieve the style class bag, if requested.
1316     const ResTable::bag_entry* styleAttrStart = NULL;
1317     uint32_t styleTypeSetFlags = 0;
1318     bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
1319     styleTypeSetFlags |= styleBagTypeSetFlags;
1320     const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
1321     BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
1322 
1323     // Retrieve the XML attributes, if requested.
1324     static const ssize_t kXmlBlock = 0x10000000;
1325     XmlAttributeFinder xmlAttrFinder(xmlParser);
1326     const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
1327 
1328     // Now iterate through all of the attributes that the client has requested,
1329     // filling in each with whatever data we can find.
1330     ssize_t block = 0;
1331     uint32_t typeSetFlags;
1332     for (jsize ii = 0; ii < NI; ii++) {
1333         const uint32_t curIdent = (uint32_t)src[ii];
1334 
1335         DEBUG_STYLES(ALOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1336 
1337         // Try to find a value for this attribute...  we prioritize values
1338         // coming from, first XML attributes, then XML style, then default
1339         // style, and finally the theme.
1340         value.dataType = Res_value::TYPE_NULL;
1341         value.data = Res_value::DATA_NULL_UNDEFINED;
1342         typeSetFlags = 0;
1343         config.density = 0;
1344 
1345         // Walk through the xml attributes looking for the requested attribute.
1346         const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
1347         if (xmlAttrIdx != xmlAttrEnd) {
1348             // We found the attribute we were looking for.
1349             block = kXmlBlock;
1350             xmlParser->getAttributeValue(xmlAttrIdx, &value);
1351             DEBUG_STYLES(ALOGI("-> From XML: type=0x%x, data=0x%08x",
1352                     value.dataType, value.data));
1353         }
1354 
1355         if (value.dataType == Res_value::TYPE_NULL) {
1356             // Walk through the style class values looking for the requested attribute.
1357             const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
1358             if (styleAttrEntry != styleAttrEnd) {
1359                 // We found the attribute we were looking for.
1360                 block = styleAttrEntry->stringBlock;
1361                 typeSetFlags = styleTypeSetFlags;
1362                 value = styleAttrEntry->map.value;
1363                 DEBUG_STYLES(ALOGI("-> From style: type=0x%x, data=0x%08x",
1364                         value.dataType, value.data));
1365             }
1366         }
1367 
1368         if (value.dataType == Res_value::TYPE_NULL) {
1369             // Walk through the default style values looking for the requested attribute.
1370             const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
1371             if (defStyleAttrEntry != defStyleAttrEnd) {
1372                 // We found the attribute we were looking for.
1373                 block = defStyleAttrEntry->stringBlock;
1374                 typeSetFlags = styleTypeSetFlags;
1375                 value = defStyleAttrEntry->map.value;
1376                 DEBUG_STYLES(ALOGI("-> From def style: type=0x%x, data=0x%08x",
1377                         value.dataType, value.data));
1378             }
1379         }
1380 
1381         uint32_t resid = 0;
1382         if (value.dataType != Res_value::TYPE_NULL) {
1383             // Take care of resolving the found resource to its final value.
1384             ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1385                     &resid, &typeSetFlags, &config);
1386             if (newBlock >= 0) {
1387                 block = newBlock;
1388             }
1389             DEBUG_STYLES(ALOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1390                     value.dataType, value.data));
1391         } else {
1392             // If we still don't have a value for this attribute, try to find
1393             // it in the theme!
1394             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1395             if (newBlock >= 0) {
1396                 DEBUG_STYLES(ALOGI("-> From theme: type=0x%x, data=0x%08x",
1397                         value.dataType, value.data));
1398                 newBlock = res.resolveReference(&value, block, &resid,
1399                         &typeSetFlags, &config);
1400 #if THROW_ON_BAD_ID
1401                 if (newBlock == BAD_INDEX) {
1402                     jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1403                     return JNI_FALSE;
1404                 }
1405 #endif
1406                 if (newBlock >= 0) {
1407                     block = newBlock;
1408                 }
1409                 DEBUG_STYLES(ALOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1410                         value.dataType, value.data));
1411             }
1412         }
1413 
1414         // Deal with the special @null value -- it turns back to TYPE_NULL.
1415         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1416             DEBUG_STYLES(ALOGI("-> Setting to @null!"));
1417             value.dataType = Res_value::TYPE_NULL;
1418             value.data = Res_value::DATA_NULL_UNDEFINED;
1419             block = kXmlBlock;
1420         }
1421 
1422         DEBUG_STYLES(ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1423                 curIdent, value.dataType, value.data));
1424 
1425         // Write the final value back to Java.
1426         dest[STYLE_TYPE] = value.dataType;
1427         dest[STYLE_DATA] = value.data;
1428         dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
1429             static_cast<jint>(res.getTableCookie(block)) : -1;
1430         dest[STYLE_RESOURCE_ID] = resid;
1431         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1432         dest[STYLE_DENSITY] = config.density;
1433 
1434         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1435             indicesIdx++;
1436             indices[indicesIdx] = ii;
1437         }
1438 
1439         dest += STYLE_NUM_ENTRIES;
1440     }
1441 
1442     res.unlock();
1443 
1444     if (indices != NULL) {
1445         indices[0] = indicesIdx;
1446         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1447     }
1448     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1449     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1450 
1451     return JNI_TRUE;
1452 }
1453 
android_content_AssetManager_retrieveAttributes(JNIEnv * env,jobject clazz,jlong xmlParserToken,jintArray attrs,jintArray outValues,jintArray outIndices)1454 static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1455                                                         jlong xmlParserToken,
1456                                                         jintArray attrs,
1457                                                         jintArray outValues,
1458                                                         jintArray outIndices)
1459 {
1460     if (xmlParserToken == 0) {
1461         jniThrowNullPointerException(env, "xmlParserToken");
1462         return JNI_FALSE;
1463     }
1464     if (attrs == NULL) {
1465         jniThrowNullPointerException(env, "attrs");
1466         return JNI_FALSE;
1467     }
1468     if (outValues == NULL) {
1469         jniThrowNullPointerException(env, "out values");
1470         return JNI_FALSE;
1471     }
1472 
1473     AssetManager* am = assetManagerForJavaObject(env, clazz);
1474     if (am == NULL) {
1475         return JNI_FALSE;
1476     }
1477     const ResTable& res(am->getResources());
1478     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1479     ResTable_config config;
1480     Res_value value;
1481 
1482     const jsize NI = env->GetArrayLength(attrs);
1483     const jsize NV = env->GetArrayLength(outValues);
1484     if (NV < (NI*STYLE_NUM_ENTRIES)) {
1485         jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
1486         return JNI_FALSE;
1487     }
1488 
1489     jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1490     if (src == NULL) {
1491         return JNI_FALSE;
1492     }
1493 
1494     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1495     jint* dest = baseDest;
1496     if (dest == NULL) {
1497         env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1498         return JNI_FALSE;
1499     }
1500 
1501     jint* indices = NULL;
1502     int indicesIdx = 0;
1503     if (outIndices != NULL) {
1504         if (env->GetArrayLength(outIndices) > NI) {
1505             indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1506         }
1507     }
1508 
1509     // Now lock down the resource object and start pulling stuff from it.
1510     res.lock();
1511 
1512     // Retrieve the XML attributes, if requested.
1513     const jsize NX = xmlParser->getAttributeCount();
1514     jsize ix=0;
1515     uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1516 
1517     static const ssize_t kXmlBlock = 0x10000000;
1518 
1519     // Now iterate through all of the attributes that the client has requested,
1520     // filling in each with whatever data we can find.
1521     ssize_t block = 0;
1522     uint32_t typeSetFlags;
1523     for (jsize ii=0; ii<NI; ii++) {
1524         const uint32_t curIdent = (uint32_t)src[ii];
1525 
1526         // Try to find a value for this attribute...
1527         value.dataType = Res_value::TYPE_NULL;
1528         value.data = Res_value::DATA_NULL_UNDEFINED;
1529         typeSetFlags = 0;
1530         config.density = 0;
1531 
1532         // Skip through XML attributes until the end or the next possible match.
1533         while (ix < NX && curIdent > curXmlAttr) {
1534             ix++;
1535             curXmlAttr = xmlParser->getAttributeNameResID(ix);
1536         }
1537         // Retrieve the current XML attribute if it matches, and step to next.
1538         if (ix < NX && curIdent == curXmlAttr) {
1539             block = kXmlBlock;
1540             xmlParser->getAttributeValue(ix, &value);
1541             ix++;
1542             curXmlAttr = xmlParser->getAttributeNameResID(ix);
1543         }
1544 
1545         //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1546         uint32_t resid = 0;
1547         if (value.dataType != Res_value::TYPE_NULL) {
1548             // Take care of resolving the found resource to its final value.
1549             //printf("Resolving attribute reference\n");
1550             ssize_t newBlock = res.resolveReference(&value, block, &resid,
1551                     &typeSetFlags, &config);
1552 #if THROW_ON_BAD_ID
1553             if (newBlock == BAD_INDEX) {
1554                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1555                 return JNI_FALSE;
1556             }
1557 #endif
1558             if (newBlock >= 0) block = newBlock;
1559         }
1560 
1561         // Deal with the special @null value -- it turns back to TYPE_NULL.
1562         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1563             value.dataType = Res_value::TYPE_NULL;
1564             value.data = Res_value::DATA_NULL_UNDEFINED;
1565         }
1566 
1567         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1568 
1569         // Write the final value back to Java.
1570         dest[STYLE_TYPE] = value.dataType;
1571         dest[STYLE_DATA] = value.data;
1572         dest[STYLE_ASSET_COOKIE] =
1573             block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
1574         dest[STYLE_RESOURCE_ID] = resid;
1575         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1576         dest[STYLE_DENSITY] = config.density;
1577 
1578         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1579             indicesIdx++;
1580             indices[indicesIdx] = ii;
1581         }
1582 
1583         dest += STYLE_NUM_ENTRIES;
1584     }
1585 
1586     res.unlock();
1587 
1588     if (indices != NULL) {
1589         indices[0] = indicesIdx;
1590         env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1591     }
1592 
1593     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1594     env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1595 
1596     return JNI_TRUE;
1597 }
1598 
android_content_AssetManager_getArraySize(JNIEnv * env,jobject clazz,jint id)1599 static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1600                                                        jint id)
1601 {
1602     AssetManager* am = assetManagerForJavaObject(env, clazz);
1603     if (am == NULL) {
1604         return 0;
1605     }
1606     const ResTable& res(am->getResources());
1607 
1608     res.lock();
1609     const ResTable::bag_entry* defStyleEnt = NULL;
1610     ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1611     res.unlock();
1612 
1613     return static_cast<jint>(bagOff);
1614 }
1615 
android_content_AssetManager_retrieveArray(JNIEnv * env,jobject clazz,jint id,jintArray outValues)1616 static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1617                                                         jint id,
1618                                                         jintArray outValues)
1619 {
1620     if (outValues == NULL) {
1621         jniThrowNullPointerException(env, "out values");
1622         return JNI_FALSE;
1623     }
1624 
1625     AssetManager* am = assetManagerForJavaObject(env, clazz);
1626     if (am == NULL) {
1627         return JNI_FALSE;
1628     }
1629     const ResTable& res(am->getResources());
1630     ResTable_config config;
1631     Res_value value;
1632     ssize_t block;
1633 
1634     const jsize NV = env->GetArrayLength(outValues);
1635 
1636     jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1637     jint* dest = baseDest;
1638     if (dest == NULL) {
1639         jniThrowException(env, "java/lang/OutOfMemoryError", "");
1640         return JNI_FALSE;
1641     }
1642 
1643     // Now lock down the resource object and start pulling stuff from it.
1644     res.lock();
1645 
1646     const ResTable::bag_entry* arrayEnt = NULL;
1647     uint32_t arrayTypeSetFlags = 0;
1648     ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1649     const ResTable::bag_entry* endArrayEnt = arrayEnt +
1650         (bagOff >= 0 ? bagOff : 0);
1651 
1652     int i = 0;
1653     uint32_t typeSetFlags;
1654     while (i < NV && arrayEnt < endArrayEnt) {
1655         block = arrayEnt->stringBlock;
1656         typeSetFlags = arrayTypeSetFlags;
1657         config.density = 0;
1658         value = arrayEnt->map.value;
1659 
1660         uint32_t resid = 0;
1661         if (value.dataType != Res_value::TYPE_NULL) {
1662             // Take care of resolving the found resource to its final value.
1663             //printf("Resolving attribute reference\n");
1664             ssize_t newBlock = res.resolveReference(&value, block, &resid,
1665                     &typeSetFlags, &config);
1666 #if THROW_ON_BAD_ID
1667             if (newBlock == BAD_INDEX) {
1668                 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1669                 return JNI_FALSE;
1670             }
1671 #endif
1672             if (newBlock >= 0) block = newBlock;
1673         }
1674 
1675         // Deal with the special @null value -- it turns back to TYPE_NULL.
1676         if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1677             value.dataType = Res_value::TYPE_NULL;
1678             value.data = Res_value::DATA_NULL_UNDEFINED;
1679         }
1680 
1681         //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1682 
1683         // Write the final value back to Java.
1684         dest[STYLE_TYPE] = value.dataType;
1685         dest[STYLE_DATA] = value.data;
1686         dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
1687         dest[STYLE_RESOURCE_ID] = resid;
1688         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1689         dest[STYLE_DENSITY] = config.density;
1690         dest += STYLE_NUM_ENTRIES;
1691         i+= STYLE_NUM_ENTRIES;
1692         arrayEnt++;
1693     }
1694 
1695     i /= STYLE_NUM_ENTRIES;
1696 
1697     res.unlock();
1698 
1699     env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1700 
1701     return i;
1702 }
1703 
android_content_AssetManager_openXmlAssetNative(JNIEnv * env,jobject clazz,jint cookie,jstring fileName)1704 static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1705                                                          jint cookie,
1706                                                          jstring fileName)
1707 {
1708     AssetManager* am = assetManagerForJavaObject(env, clazz);
1709     if (am == NULL) {
1710         return 0;
1711     }
1712 
1713     ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1714 
1715     ScopedUtfChars fileName8(env, fileName);
1716     if (fileName8.c_str() == NULL) {
1717         return 0;
1718     }
1719 
1720     int32_t assetCookie = static_cast<int32_t>(cookie);
1721     Asset* a = assetCookie
1722         ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1723         : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
1724 
1725     if (a == NULL) {
1726         jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
1727         return 0;
1728     }
1729 
1730     const DynamicRefTable* dynamicRefTable =
1731             am->getResources().getDynamicRefTableForCookie(assetCookie);
1732     ResXMLTree* block = new ResXMLTree(dynamicRefTable);
1733     status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1734     a->close();
1735     delete a;
1736 
1737     if (err != NO_ERROR) {
1738         jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1739         return 0;
1740     }
1741 
1742     return reinterpret_cast<jlong>(block);
1743 }
1744 
android_content_AssetManager_getArrayStringInfo(JNIEnv * env,jobject clazz,jint arrayResId)1745 static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1746                                                                  jint arrayResId)
1747 {
1748     AssetManager* am = assetManagerForJavaObject(env, clazz);
1749     if (am == NULL) {
1750         return NULL;
1751     }
1752     const ResTable& res(am->getResources());
1753 
1754     const ResTable::bag_entry* startOfBag;
1755     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1756     if (N < 0) {
1757         return NULL;
1758     }
1759 
1760     jintArray array = env->NewIntArray(N * 2);
1761     if (array == NULL) {
1762         res.unlockBag(startOfBag);
1763         return NULL;
1764     }
1765 
1766     Res_value value;
1767     const ResTable::bag_entry* bag = startOfBag;
1768     for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1769         jint stringIndex = -1;
1770         jint stringBlock = 0;
1771         value = bag->map.value;
1772 
1773         // Take care of resolving the found resource to its final value.
1774         stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1775         if (value.dataType == Res_value::TYPE_STRING) {
1776             stringIndex = value.data;
1777         }
1778 
1779 #if THROW_ON_BAD_ID
1780         if (stringBlock == BAD_INDEX) {
1781             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1782             return array;
1783         }
1784 #endif
1785 
1786         //todo: It might be faster to allocate a C array to contain
1787         //      the blocknums and indices, put them in there and then
1788         //      do just one SetIntArrayRegion()
1789         env->SetIntArrayRegion(array, j, 1, &stringBlock);
1790         env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1791         j = j + 2;
1792     }
1793     res.unlockBag(startOfBag);
1794     return array;
1795 }
1796 
android_content_AssetManager_getArrayStringResource(JNIEnv * env,jobject clazz,jint arrayResId)1797 static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1798                                                                         jint arrayResId)
1799 {
1800     AssetManager* am = assetManagerForJavaObject(env, clazz);
1801     if (am == NULL) {
1802         return NULL;
1803     }
1804     const ResTable& res(am->getResources());
1805 
1806     const ResTable::bag_entry* startOfBag;
1807     const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1808     if (N < 0) {
1809         return NULL;
1810     }
1811 
1812     jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
1813     if (env->ExceptionCheck()) {
1814         res.unlockBag(startOfBag);
1815         return NULL;
1816     }
1817 
1818     Res_value value;
1819     const ResTable::bag_entry* bag = startOfBag;
1820     size_t strLen = 0;
1821     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1822         value = bag->map.value;
1823         jstring str = NULL;
1824 
1825         // Take care of resolving the found resource to its final value.
1826         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1827 #if THROW_ON_BAD_ID
1828         if (block == BAD_INDEX) {
1829             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1830             return array;
1831         }
1832 #endif
1833         if (value.dataType == Res_value::TYPE_STRING) {
1834             const ResStringPool* pool = res.getTableStringBlock(block);
1835             const char* str8 = pool->string8At(value.data, &strLen);
1836             if (str8 != NULL) {
1837                 str = env->NewStringUTF(str8);
1838             } else {
1839                 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1840                 str = env->NewString(str16, strLen);
1841             }
1842 
1843             // If one of our NewString{UTF} calls failed due to memory, an
1844             // exception will be pending.
1845             if (env->ExceptionCheck()) {
1846                 res.unlockBag(startOfBag);
1847                 return NULL;
1848             }
1849 
1850             env->SetObjectArrayElement(array, i, str);
1851 
1852             // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1853             // If we have a large amount of strings in our array, we might
1854             // overflow the local reference table of the VM.
1855             env->DeleteLocalRef(str);
1856         }
1857     }
1858     res.unlockBag(startOfBag);
1859     return array;
1860 }
1861 
android_content_AssetManager_getArrayIntResource(JNIEnv * env,jobject clazz,jint arrayResId)1862 static jintArray android_content_AssetManager_getArrayIntResource(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     jintArray array = env->NewIntArray(N);
1878     if (array == NULL) {
1879         res.unlockBag(startOfBag);
1880         return NULL;
1881     }
1882 
1883     Res_value value;
1884     const ResTable::bag_entry* bag = startOfBag;
1885     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1886         value = bag->map.value;
1887 
1888         // Take care of resolving the found resource to its final value.
1889         ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1890 #if THROW_ON_BAD_ID
1891         if (block == BAD_INDEX) {
1892             jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1893             return array;
1894         }
1895 #endif
1896         if (value.dataType >= Res_value::TYPE_FIRST_INT
1897                 && value.dataType <= Res_value::TYPE_LAST_INT) {
1898             int intVal = value.data;
1899             env->SetIntArrayRegion(array, i, 1, &intVal);
1900         }
1901     }
1902     res.unlockBag(startOfBag);
1903     return array;
1904 }
1905 
android_content_AssetManager_getStyleAttributes(JNIEnv * env,jobject clazz,jint styleId)1906 static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
1907                                                                  jint styleId)
1908 {
1909     AssetManager* am = assetManagerForJavaObject(env, clazz);
1910     if (am == NULL) {
1911         return NULL;
1912     }
1913     const ResTable& res(am->getResources());
1914 
1915     const ResTable::bag_entry* startOfBag;
1916     const ssize_t N = res.lockBag(styleId, &startOfBag);
1917     if (N < 0) {
1918         return NULL;
1919     }
1920 
1921     jintArray array = env->NewIntArray(N);
1922     if (array == NULL) {
1923         res.unlockBag(startOfBag);
1924         return NULL;
1925     }
1926 
1927     Res_value value;
1928     const ResTable::bag_entry* bag = startOfBag;
1929     for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1930         int resourceId = bag->map.name.ident;
1931         env->SetIntArrayRegion(array, i, 1, &resourceId);
1932     }
1933     res.unlockBag(startOfBag);
1934     return array;
1935 }
1936 
android_content_AssetManager_init(JNIEnv * env,jobject clazz,jboolean isSystem)1937 static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
1938 {
1939     if (isSystem) {
1940         verifySystemIdmaps();
1941     }
1942     AssetManager* am = new AssetManager();
1943     if (am == NULL) {
1944         jniThrowException(env, "java/lang/OutOfMemoryError", "");
1945         return;
1946     }
1947 
1948     am->addDefaultAssets();
1949 
1950     ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1951     env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
1952 }
1953 
android_content_AssetManager_destroy(JNIEnv * env,jobject clazz)1954 static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1955 {
1956     AssetManager* am = (AssetManager*)
1957         (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
1958     ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1959     if (am != NULL) {
1960         delete am;
1961         env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
1962     }
1963 }
1964 
android_content_AssetManager_getGlobalAssetCount(JNIEnv * env,jobject clazz)1965 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1966 {
1967     return Asset::getGlobalCount();
1968 }
1969 
android_content_AssetManager_getAssetAllocations(JNIEnv * env,jobject clazz)1970 static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1971 {
1972     String8 alloc = Asset::getAssetAllocations();
1973     if (alloc.length() <= 0) {
1974         return NULL;
1975     }
1976 
1977     jstring str = env->NewStringUTF(alloc.string());
1978     return str;
1979 }
1980 
android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv * env,jobject clazz)1981 static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1982 {
1983     return AssetManager::getGlobalCount();
1984 }
1985 
1986 // ----------------------------------------------------------------------------
1987 
1988 /*
1989  * JNI registration.
1990  */
1991 static JNINativeMethod gAssetManagerMethods[] = {
1992     /* name, signature, funcPtr */
1993 
1994     // Basic asset stuff.
1995     { "openAsset",      "(Ljava/lang/String;I)J",
1996         (void*) android_content_AssetManager_openAsset },
1997     { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1998         (void*) android_content_AssetManager_openAssetFd },
1999     { "openNonAssetNative", "(ILjava/lang/String;I)J",
2000         (void*) android_content_AssetManager_openNonAssetNative },
2001     { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
2002         (void*) android_content_AssetManager_openNonAssetFdNative },
2003     { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
2004         (void*) android_content_AssetManager_list },
2005     { "destroyAsset",   "(J)V",
2006         (void*) android_content_AssetManager_destroyAsset },
2007     { "readAssetChar",  "(J)I",
2008         (void*) android_content_AssetManager_readAssetChar },
2009     { "readAsset",      "(J[BII)I",
2010         (void*) android_content_AssetManager_readAsset },
2011     { "seekAsset",      "(JJI)J",
2012         (void*) android_content_AssetManager_seekAsset },
2013     { "getAssetLength", "(J)J",
2014         (void*) android_content_AssetManager_getAssetLength },
2015     { "getAssetRemainingLength", "(J)J",
2016         (void*) android_content_AssetManager_getAssetRemainingLength },
2017     { "addAssetPathNative", "(Ljava/lang/String;)I",
2018         (void*) android_content_AssetManager_addAssetPath },
2019     { "addOverlayPath",   "(Ljava/lang/String;)I",
2020         (void*) android_content_AssetManager_addOverlayPath },
2021     { "isUpToDate",     "()Z",
2022         (void*) android_content_AssetManager_isUpToDate },
2023 
2024     // Resources.
2025     { "setLocale",      "(Ljava/lang/String;)V",
2026         (void*) android_content_AssetManager_setLocale },
2027     { "getLocales",      "()[Ljava/lang/String;",
2028         (void*) android_content_AssetManager_getLocales },
2029     { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
2030         (void*) android_content_AssetManager_setConfiguration },
2031     { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
2032         (void*) android_content_AssetManager_getResourceIdentifier },
2033     { "getResourceName","(I)Ljava/lang/String;",
2034         (void*) android_content_AssetManager_getResourceName },
2035     { "getResourcePackageName","(I)Ljava/lang/String;",
2036         (void*) android_content_AssetManager_getResourcePackageName },
2037     { "getResourceTypeName","(I)Ljava/lang/String;",
2038         (void*) android_content_AssetManager_getResourceTypeName },
2039     { "getResourceEntryName","(I)Ljava/lang/String;",
2040         (void*) android_content_AssetManager_getResourceEntryName },
2041     { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
2042         (void*) android_content_AssetManager_loadResourceValue },
2043     { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
2044         (void*) android_content_AssetManager_loadResourceBagValue },
2045     { "getStringBlockCount","()I",
2046         (void*) android_content_AssetManager_getStringBlockCount },
2047     { "getNativeStringBlock","(I)J",
2048         (void*) android_content_AssetManager_getNativeStringBlock },
2049     { "getCookieName","(I)Ljava/lang/String;",
2050         (void*) android_content_AssetManager_getCookieName },
2051     { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
2052         (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
2053 
2054     // Themes.
2055     { "newTheme", "()J",
2056         (void*) android_content_AssetManager_newTheme },
2057     { "deleteTheme", "(J)V",
2058         (void*) android_content_AssetManager_deleteTheme },
2059     { "applyThemeStyle", "(JIZ)V",
2060         (void*) android_content_AssetManager_applyThemeStyle },
2061     { "copyTheme", "(JJ)V",
2062         (void*) android_content_AssetManager_copyTheme },
2063     { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
2064         (void*) android_content_AssetManager_loadThemeAttributeValue },
2065     { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
2066         (void*) android_content_AssetManager_dumpTheme },
2067     { "applyStyle","(JIIJ[I[I[I)Z",
2068         (void*) android_content_AssetManager_applyStyle },
2069     { "resolveAttrs","(JII[I[I[I[I)Z",
2070         (void*) android_content_AssetManager_resolveAttrs },
2071     { "retrieveAttributes","(J[I[I[I)Z",
2072         (void*) android_content_AssetManager_retrieveAttributes },
2073     { "getArraySize","(I)I",
2074         (void*) android_content_AssetManager_getArraySize },
2075     { "retrieveArray","(I[I)I",
2076         (void*) android_content_AssetManager_retrieveArray },
2077 
2078     // XML files.
2079     { "openXmlAssetNative", "(ILjava/lang/String;)J",
2080         (void*) android_content_AssetManager_openXmlAssetNative },
2081 
2082     // Arrays.
2083     { "getArrayStringResource","(I)[Ljava/lang/String;",
2084         (void*) android_content_AssetManager_getArrayStringResource },
2085     { "getArrayStringInfo","(I)[I",
2086         (void*) android_content_AssetManager_getArrayStringInfo },
2087     { "getArrayIntResource","(I)[I",
2088         (void*) android_content_AssetManager_getArrayIntResource },
2089     { "getStyleAttributes","(I)[I",
2090         (void*) android_content_AssetManager_getStyleAttributes },
2091 
2092     // Bookkeeping.
2093     { "init",           "(Z)V",
2094         (void*) android_content_AssetManager_init },
2095     { "destroy",        "()V",
2096         (void*) android_content_AssetManager_destroy },
2097     { "getGlobalAssetCount", "()I",
2098         (void*) android_content_AssetManager_getGlobalAssetCount },
2099     { "getAssetAllocations", "()Ljava/lang/String;",
2100         (void*) android_content_AssetManager_getAssetAllocations },
2101     { "getGlobalAssetManagerCount", "()I",
2102         (void*) android_content_AssetManager_getGlobalAssetCount },
2103 };
2104 
register_android_content_AssetManager(JNIEnv * env)2105 int register_android_content_AssetManager(JNIEnv* env)
2106 {
2107     jclass typedValue = env->FindClass("android/util/TypedValue");
2108     LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
2109     gTypedValueOffsets.mType
2110         = env->GetFieldID(typedValue, "type", "I");
2111     LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
2112     gTypedValueOffsets.mData
2113         = env->GetFieldID(typedValue, "data", "I");
2114     LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
2115     gTypedValueOffsets.mString
2116         = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
2117     LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
2118     gTypedValueOffsets.mAssetCookie
2119         = env->GetFieldID(typedValue, "assetCookie", "I");
2120     LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
2121     gTypedValueOffsets.mResourceId
2122         = env->GetFieldID(typedValue, "resourceId", "I");
2123     LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
2124     gTypedValueOffsets.mChangingConfigurations
2125         = env->GetFieldID(typedValue, "changingConfigurations", "I");
2126     LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
2127     gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
2128     LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
2129 
2130     jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
2131     LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
2132     gAssetFileDescriptorOffsets.mFd
2133         = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
2134     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
2135     gAssetFileDescriptorOffsets.mStartOffset
2136         = env->GetFieldID(assetFd, "mStartOffset", "J");
2137     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
2138     gAssetFileDescriptorOffsets.mLength
2139         = env->GetFieldID(assetFd, "mLength", "J");
2140     LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
2141 
2142     jclass assetManager = env->FindClass("android/content/res/AssetManager");
2143     LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
2144     gAssetManagerOffsets.mObject
2145         = env->GetFieldID(assetManager, "mObject", "J");
2146     LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
2147 
2148     jclass stringClass = env->FindClass("java/lang/String");
2149     LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
2150     g_stringClass = (jclass)env->NewGlobalRef(stringClass);
2151     LOG_FATAL_IF(g_stringClass == NULL, "Unable to create global reference for class java/lang/String");
2152 
2153     jclass sparseArrayClass = env->FindClass("android/util/SparseArray");
2154     LOG_FATAL_IF(sparseArrayClass == NULL, "Unable to find class android/util/SparseArray");
2155     gSparseArrayOffsets.classObject = (jclass) env->NewGlobalRef(sparseArrayClass);
2156     gSparseArrayOffsets.constructor =
2157             env->GetMethodID(gSparseArrayOffsets.classObject, "<init>", "()V");
2158     LOG_FATAL_IF(gSparseArrayOffsets.constructor == NULL, "Unable to find SparseArray.<init>()");
2159     gSparseArrayOffsets.put =
2160             env->GetMethodID(gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
2161     LOG_FATAL_IF(gSparseArrayOffsets.put == NULL, "Unable to find SparseArray.put(int, V)");
2162 
2163     return AndroidRuntime::registerNativeMethods(env,
2164             "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
2165 }
2166 
2167 }; // namespace android
2168