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