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