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