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