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