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