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