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 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 611 static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz) 612 { 613 return getLocales(env, clazz, true /* include system locales */); 614 } 615 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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: 1115 XmlAttributeFinder(const ResXMLParser* parser) 1116 : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0) 1117 , mParser(parser) {} 1118 1119 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: 1129 BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) 1130 : BackTrackingAttributeFinder(start, end) {} 1131 1132 inline uint32_t getAttribute(const ResTable::bag_entry* entry) const { 1133 return entry->map.name.ident; 1134 } 1135 }; 1136 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 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 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 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 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 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 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 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 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 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 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 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 2105 static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz) 2106 { 2107 return Asset::getGlobalCount(); 2108 } 2109 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 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 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