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