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