android_util_AssetManager.cpp revision 404eb9ce51a07fb990556f34fdef40c071da5539
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 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; 54 55// ---------------------------------------------------------------------------- 56 57static 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 68static struct assetfiledescriptor_offsets_t 69{ 70 jfieldID mFd; 71 jfieldID mStartOffset; 72 jfieldID mLength; 73} gAssetFileDescriptorOffsets; 74 75static struct assetmanager_offsets_t 76{ 77 jfieldID mObject; 78} gAssetManagerOffsets; 79 80static struct sparsearray_offsets_t 81{ 82 jclass classObject; 83 jmethodID constructor; 84 jmethodID put; 85} gSparseArrayOffsets; 86 87static struct configuration_offsets_t 88{ 89 jclass classObject; 90 jmethodID constructor; 91 jfieldID mSmallestScreenWidthDpOffset; 92 jfieldID mScreenWidthDpOffset; 93 jfieldID mScreenHeightDpOffset; 94} gConfigurationOffsets; 95 96jclass g_stringClass = NULL; 97 98// ---------------------------------------------------------------------------- 99 100static 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 104jint 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. 123static 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 211AssetManager* 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 222static 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 256static 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 288static 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 315static 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 353static 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 384static 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 429static 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 444static 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 459static 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 492static 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 507static 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 520static 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 533static 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 552static 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 571static 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 580static 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 610static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz) 611{ 612 return getLocales(env, clazz, true /* include system locales */); 613} 614 615static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz) 616{ 617 return getLocales(env, clazz, false /* don't include system locales */); 618} 619 620static 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 635static 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 657static 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 670static 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 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.sdkVersion = (uint16_t)sdkVersion; 712 config.minorVersion = 0; 713 714 // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer 715 // in C++. We must extract the round qualifier out of the Java screenLayout and put it 716 // into screenLayout2. 717 config.screenLayout2 = 718 (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift); 719 720 am->setConfiguration(config, locale8); 721 722 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8); 723} 724 725static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz, 726 jstring name, 727 jstring defType, 728 jstring defPackage) 729{ 730 ScopedStringChars name16(env, name); 731 if (name16.get() == NULL) { 732 return 0; 733 } 734 735 AssetManager* am = assetManagerForJavaObject(env, clazz); 736 if (am == NULL) { 737 return 0; 738 } 739 740 const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType) 741 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL)) 742 : NULL; 743 jsize defTypeLen = defType 744 ? env->GetStringLength(defType) : 0; 745 const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage) 746 ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage, 747 NULL)) 748 : NULL; 749 jsize defPackageLen = defPackage 750 ? env->GetStringLength(defPackage) : 0; 751 752 jint ident = am->getResources().identifierForName( 753 reinterpret_cast<const char16_t*>(name16.get()), name16.size(), 754 defType16, defTypeLen, defPackage16, defPackageLen); 755 756 if (defPackage16) { 757 env->ReleaseStringChars(defPackage, 758 reinterpret_cast<const jchar*>(defPackage16)); 759 } 760 if (defType16) { 761 env->ReleaseStringChars(defType, 762 reinterpret_cast<const jchar*>(defType16)); 763 } 764 765 return ident; 766} 767 768static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz, 769 jint resid) 770{ 771 AssetManager* am = assetManagerForJavaObject(env, clazz); 772 if (am == NULL) { 773 return NULL; 774 } 775 776 ResTable::resource_name name; 777 if (!am->getResources().getResourceName(resid, true, &name)) { 778 return NULL; 779 } 780 781 String16 str; 782 if (name.package != NULL) { 783 str.setTo(name.package, name.packageLen); 784 } 785 if (name.type8 != NULL || name.type != NULL) { 786 if (str.size() > 0) { 787 char16_t div = ':'; 788 str.append(&div, 1); 789 } 790 if (name.type8 != NULL) { 791 str.append(String16(name.type8, name.typeLen)); 792 } else { 793 str.append(name.type, name.typeLen); 794 } 795 } 796 if (name.name8 != NULL || name.name != NULL) { 797 if (str.size() > 0) { 798 char16_t div = '/'; 799 str.append(&div, 1); 800 } 801 if (name.name8 != NULL) { 802 str.append(String16(name.name8, name.nameLen)); 803 } else { 804 str.append(name.name, name.nameLen); 805 } 806 } 807 808 return env->NewString((const jchar*)str.string(), str.size()); 809} 810 811static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz, 812 jint resid) 813{ 814 AssetManager* am = assetManagerForJavaObject(env, clazz); 815 if (am == NULL) { 816 return NULL; 817 } 818 819 ResTable::resource_name name; 820 if (!am->getResources().getResourceName(resid, true, &name)) { 821 return NULL; 822 } 823 824 if (name.package != NULL) { 825 return env->NewString((const jchar*)name.package, name.packageLen); 826 } 827 828 return NULL; 829} 830 831static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz, 832 jint resid) 833{ 834 AssetManager* am = assetManagerForJavaObject(env, clazz); 835 if (am == NULL) { 836 return NULL; 837 } 838 839 ResTable::resource_name name; 840 if (!am->getResources().getResourceName(resid, true, &name)) { 841 return NULL; 842 } 843 844 if (name.type8 != NULL) { 845 return env->NewStringUTF(name.type8); 846 } 847 848 if (name.type != NULL) { 849 return env->NewString((const jchar*)name.type, name.typeLen); 850 } 851 852 return NULL; 853} 854 855static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz, 856 jint resid) 857{ 858 AssetManager* am = assetManagerForJavaObject(env, clazz); 859 if (am == NULL) { 860 return NULL; 861 } 862 863 ResTable::resource_name name; 864 if (!am->getResources().getResourceName(resid, true, &name)) { 865 return NULL; 866 } 867 868 if (name.name8 != NULL) { 869 return env->NewStringUTF(name.name8); 870 } 871 872 if (name.name != NULL) { 873 return env->NewString((const jchar*)name.name, name.nameLen); 874 } 875 876 return NULL; 877} 878 879static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz, 880 jint ident, 881 jshort density, 882 jobject outValue, 883 jboolean resolve) 884{ 885 if (outValue == NULL) { 886 jniThrowNullPointerException(env, "outValue"); 887 return 0; 888 } 889 AssetManager* am = assetManagerForJavaObject(env, clazz); 890 if (am == NULL) { 891 return 0; 892 } 893 const ResTable& res(am->getResources()); 894 895 Res_value value; 896 ResTable_config config; 897 uint32_t typeSpecFlags; 898 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config); 899 if (kThrowOnBadId) { 900 if (block == BAD_INDEX) { 901 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 902 return 0; 903 } 904 } 905 uint32_t ref = ident; 906 if (resolve) { 907 block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config); 908 if (kThrowOnBadId) { 909 if (block == BAD_INDEX) { 910 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 911 return 0; 912 } 913 } 914 } 915 if (block >= 0) { 916 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config); 917 } 918 919 return static_cast<jint>(block); 920} 921 922static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz, 923 jint ident, jint bagEntryId, 924 jobject outValue, jboolean resolve) 925{ 926 AssetManager* am = assetManagerForJavaObject(env, clazz); 927 if (am == NULL) { 928 return 0; 929 } 930 const ResTable& res(am->getResources()); 931 932 // Now lock down the resource object and start pulling stuff from it. 933 res.lock(); 934 935 ssize_t block = -1; 936 Res_value value; 937 938 const ResTable::bag_entry* entry = NULL; 939 uint32_t typeSpecFlags; 940 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags); 941 942 for (ssize_t i=0; i<entryCount; i++) { 943 if (((uint32_t)bagEntryId) == entry->map.name.ident) { 944 block = entry->stringBlock; 945 value = entry->map.value; 946 } 947 entry++; 948 } 949 950 res.unlock(); 951 952 if (block < 0) { 953 return static_cast<jint>(block); 954 } 955 956 uint32_t ref = ident; 957 if (resolve) { 958 block = res.resolveReference(&value, block, &ref, &typeSpecFlags); 959 if (kThrowOnBadId) { 960 if (block == BAD_INDEX) { 961 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 962 return 0; 963 } 964 } 965 } 966 if (block >= 0) { 967 return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags); 968 } 969 970 return static_cast<jint>(block); 971} 972 973static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz) 974{ 975 AssetManager* am = assetManagerForJavaObject(env, clazz); 976 if (am == NULL) { 977 return 0; 978 } 979 return am->getResources().getTableCount(); 980} 981 982static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz, 983 jint block) 984{ 985 AssetManager* am = assetManagerForJavaObject(env, clazz); 986 if (am == NULL) { 987 return 0; 988 } 989 return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block)); 990} 991 992static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz, 993 jint cookie) 994{ 995 AssetManager* am = assetManagerForJavaObject(env, clazz); 996 if (am == NULL) { 997 return NULL; 998 } 999 String8 name(am->getAssetPath(static_cast<int32_t>(cookie))); 1000 if (name.length() == 0) { 1001 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name"); 1002 return NULL; 1003 } 1004 jstring str = env->NewStringUTF(name.string()); 1005 return str; 1006} 1007 1008static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz) 1009{ 1010 AssetManager* am = assetManagerForJavaObject(env, clazz); 1011 if (am == NULL) { 1012 return 0; 1013 } 1014 1015 const ResTable& res = am->getResources(); 1016 1017 jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject, 1018 gSparseArrayOffsets.constructor); 1019 const size_t N = res.getBasePackageCount(); 1020 for (size_t i = 0; i < N; i++) { 1021 const String16 name = res.getBasePackageName(i); 1022 env->CallVoidMethod( 1023 sparseArray, gSparseArrayOffsets.put, 1024 static_cast<jint>(res.getBasePackageId(i)), 1025 env->NewString(reinterpret_cast<const jchar*>(name.string()), 1026 name.size())); 1027 } 1028 return sparseArray; 1029} 1030 1031static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz) 1032{ 1033 AssetManager* am = assetManagerForJavaObject(env, clazz); 1034 if (am == NULL) { 1035 return 0; 1036 } 1037 return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources())); 1038} 1039 1040static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz, 1041 jlong themeHandle) 1042{ 1043 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1044 delete theme; 1045} 1046 1047static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz, 1048 jlong themeHandle, 1049 jint styleRes, 1050 jboolean force) 1051{ 1052 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1053 theme->applyStyle(styleRes, force ? true : false); 1054} 1055 1056static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz, 1057 jlong destHandle, jlong srcHandle) 1058{ 1059 ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle); 1060 ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle); 1061 dest->setTo(*src); 1062} 1063 1064static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle) 1065{ 1066 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1067 theme->clear(); 1068} 1069 1070static jint android_content_AssetManager_loadThemeAttributeValue( 1071 JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve) 1072{ 1073 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1074 const ResTable& res(theme->getResTable()); 1075 1076 Res_value value; 1077 // XXX value could be different in different configs! 1078 uint32_t typeSpecFlags = 0; 1079 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags); 1080 uint32_t ref = 0; 1081 if (resolve) { 1082 block = res.resolveReference(&value, block, &ref, &typeSpecFlags); 1083 if (kThrowOnBadId) { 1084 if (block == BAD_INDEX) { 1085 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1086 return 0; 1087 } 1088 } 1089 } 1090 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block; 1091} 1092 1093static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz, 1094 jlong themeHandle) 1095{ 1096 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1097 return theme->getChangingConfigurations(); 1098} 1099 1100static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz, 1101 jlong themeHandle, jint pri, 1102 jstring tag, jstring prefix) 1103{ 1104 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle); 1105 const ResTable& res(theme->getResTable()); 1106 (void)res; 1107 1108 // XXX Need to use params. 1109 theme->dumpToLog(); 1110} 1111 1112static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz, 1113 jlong themeToken, 1114 jint defStyleAttr, 1115 jint defStyleRes, 1116 jintArray inValues, 1117 jintArray attrs, 1118 jintArray outValues, 1119 jintArray outIndices) 1120{ 1121 if (themeToken == 0) { 1122 jniThrowNullPointerException(env, "theme token"); 1123 return JNI_FALSE; 1124 } 1125 if (attrs == NULL) { 1126 jniThrowNullPointerException(env, "attrs"); 1127 return JNI_FALSE; 1128 } 1129 if (outValues == NULL) { 1130 jniThrowNullPointerException(env, "out values"); 1131 return JNI_FALSE; 1132 } 1133 1134 const jsize NI = env->GetArrayLength(attrs); 1135 const jsize NV = env->GetArrayLength(outValues); 1136 if (NV < (NI*STYLE_NUM_ENTRIES)) { 1137 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small"); 1138 return JNI_FALSE; 1139 } 1140 1141 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 1142 if (src == NULL) { 1143 return JNI_FALSE; 1144 } 1145 1146 jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0); 1147 const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues); 1148 1149 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1150 if (baseDest == NULL) { 1151 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1152 return JNI_FALSE; 1153 } 1154 1155 jint* indices = NULL; 1156 if (outIndices != NULL) { 1157 if (env->GetArrayLength(outIndices) > NI) { 1158 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 1159 } 1160 } 1161 1162 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken); 1163 bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes, 1164 (uint32_t*) srcValues, NSV, 1165 (uint32_t*) src, NI, 1166 (uint32_t*) baseDest, 1167 (uint32_t*) indices); 1168 1169 if (indices != NULL) { 1170 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1171 } 1172 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1173 env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0); 1174 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1175 return result ? JNI_TRUE : JNI_FALSE; 1176} 1177 1178static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz, 1179 jlong themeToken, 1180 jint defStyleAttr, 1181 jint defStyleRes, 1182 jlong xmlParserToken, 1183 jintArray attrs, 1184 jintArray outValues, 1185 jintArray outIndices) 1186{ 1187 if (themeToken == 0) { 1188 jniThrowNullPointerException(env, "theme token"); 1189 return JNI_FALSE; 1190 } 1191 if (attrs == NULL) { 1192 jniThrowNullPointerException(env, "attrs"); 1193 return JNI_FALSE; 1194 } 1195 if (outValues == NULL) { 1196 jniThrowNullPointerException(env, "out values"); 1197 return JNI_FALSE; 1198 } 1199 1200 const jsize NI = env->GetArrayLength(attrs); 1201 const jsize NV = env->GetArrayLength(outValues); 1202 if (NV < (NI*STYLE_NUM_ENTRIES)) { 1203 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small"); 1204 return JNI_FALSE; 1205 } 1206 1207 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 1208 if (src == NULL) { 1209 return JNI_FALSE; 1210 } 1211 1212 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1213 if (baseDest == NULL) { 1214 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1215 return JNI_FALSE; 1216 } 1217 1218 jint* indices = NULL; 1219 if (outIndices != NULL) { 1220 if (env->GetArrayLength(outIndices) > NI) { 1221 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 1222 } 1223 } 1224 1225 ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken); 1226 ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken); 1227 bool result = ApplyStyle(theme, xmlParser, 1228 defStyleAttr, defStyleRes, 1229 (uint32_t*) src, NI, 1230 (uint32_t*) baseDest, 1231 (uint32_t*) indices); 1232 1233 if (indices != NULL) { 1234 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1235 } 1236 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1237 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1238 return result ? JNI_TRUE : JNI_FALSE; 1239} 1240 1241static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz, 1242 jlong xmlParserToken, 1243 jintArray attrs, 1244 jintArray outValues, 1245 jintArray outIndices) 1246{ 1247 if (xmlParserToken == 0) { 1248 jniThrowNullPointerException(env, "xmlParserToken"); 1249 return JNI_FALSE; 1250 } 1251 if (attrs == NULL) { 1252 jniThrowNullPointerException(env, "attrs"); 1253 return JNI_FALSE; 1254 } 1255 if (outValues == NULL) { 1256 jniThrowNullPointerException(env, "out values"); 1257 return JNI_FALSE; 1258 } 1259 1260 AssetManager* am = assetManagerForJavaObject(env, clazz); 1261 if (am == NULL) { 1262 return JNI_FALSE; 1263 } 1264 const ResTable& res(am->getResources()); 1265 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; 1266 1267 const jsize NI = env->GetArrayLength(attrs); 1268 const jsize NV = env->GetArrayLength(outValues); 1269 if (NV < (NI*STYLE_NUM_ENTRIES)) { 1270 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small"); 1271 return JNI_FALSE; 1272 } 1273 1274 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 1275 if (src == NULL) { 1276 return JNI_FALSE; 1277 } 1278 1279 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1280 if (baseDest == NULL) { 1281 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1282 return JNI_FALSE; 1283 } 1284 1285 jint* indices = NULL; 1286 if (outIndices != NULL) { 1287 if (env->GetArrayLength(outIndices) > NI) { 1288 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 1289 } 1290 } 1291 1292 bool result = RetrieveAttributes(&res, xmlParser, 1293 (uint32_t*) src, NI, 1294 (uint32_t*) baseDest, 1295 (uint32_t*) indices); 1296 1297 if (indices != NULL) { 1298 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1299 } 1300 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1301 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1302 return result ? JNI_TRUE : JNI_FALSE; 1303} 1304 1305static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz, 1306 jint id) 1307{ 1308 AssetManager* am = assetManagerForJavaObject(env, clazz); 1309 if (am == NULL) { 1310 return 0; 1311 } 1312 const ResTable& res(am->getResources()); 1313 1314 res.lock(); 1315 const ResTable::bag_entry* defStyleEnt = NULL; 1316 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt); 1317 res.unlock(); 1318 1319 return static_cast<jint>(bagOff); 1320} 1321 1322static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz, 1323 jint id, 1324 jintArray outValues) 1325{ 1326 if (outValues == NULL) { 1327 jniThrowNullPointerException(env, "out values"); 1328 return JNI_FALSE; 1329 } 1330 1331 AssetManager* am = assetManagerForJavaObject(env, clazz); 1332 if (am == NULL) { 1333 return JNI_FALSE; 1334 } 1335 const ResTable& res(am->getResources()); 1336 ResTable_config config; 1337 Res_value value; 1338 ssize_t block; 1339 1340 const jsize NV = env->GetArrayLength(outValues); 1341 1342 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1343 jint* dest = baseDest; 1344 if (dest == NULL) { 1345 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1346 return JNI_FALSE; 1347 } 1348 1349 // Now lock down the resource object and start pulling stuff from it. 1350 res.lock(); 1351 1352 const ResTable::bag_entry* arrayEnt = NULL; 1353 uint32_t arrayTypeSetFlags = 0; 1354 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags); 1355 const ResTable::bag_entry* endArrayEnt = arrayEnt + 1356 (bagOff >= 0 ? bagOff : 0); 1357 1358 int i = 0; 1359 uint32_t typeSetFlags; 1360 while (i < NV && arrayEnt < endArrayEnt) { 1361 block = arrayEnt->stringBlock; 1362 typeSetFlags = arrayTypeSetFlags; 1363 config.density = 0; 1364 value = arrayEnt->map.value; 1365 1366 uint32_t resid = 0; 1367 if (value.dataType != Res_value::TYPE_NULL) { 1368 // Take care of resolving the found resource to its final value. 1369 //printf("Resolving attribute reference\n"); 1370 ssize_t newBlock = res.resolveReference(&value, block, &resid, 1371 &typeSetFlags, &config); 1372 if (kThrowOnBadId) { 1373 if (newBlock == BAD_INDEX) { 1374 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1375 return JNI_FALSE; 1376 } 1377 } 1378 if (newBlock >= 0) block = newBlock; 1379 } 1380 1381 // Deal with the special @null value -- it turns back to TYPE_NULL. 1382 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1383 value.dataType = Res_value::TYPE_NULL; 1384 value.data = Res_value::DATA_NULL_UNDEFINED; 1385 } 1386 1387 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1388 1389 // Write the final value back to Java. 1390 dest[STYLE_TYPE] = value.dataType; 1391 dest[STYLE_DATA] = value.data; 1392 dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block)); 1393 dest[STYLE_RESOURCE_ID] = resid; 1394 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1395 dest[STYLE_DENSITY] = config.density; 1396 dest += STYLE_NUM_ENTRIES; 1397 i+= STYLE_NUM_ENTRIES; 1398 arrayEnt++; 1399 } 1400 1401 i /= STYLE_NUM_ENTRIES; 1402 1403 res.unlock(); 1404 1405 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1406 1407 return i; 1408} 1409 1410static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz, 1411 jint cookie, 1412 jstring fileName) 1413{ 1414 AssetManager* am = assetManagerForJavaObject(env, clazz); 1415 if (am == NULL) { 1416 return 0; 1417 } 1418 1419 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz); 1420 1421 ScopedUtfChars fileName8(env, fileName); 1422 if (fileName8.c_str() == NULL) { 1423 return 0; 1424 } 1425 1426 int32_t assetCookie = static_cast<int32_t>(cookie); 1427 Asset* a = assetCookie 1428 ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER) 1429 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie); 1430 1431 if (a == NULL) { 1432 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str()); 1433 return 0; 1434 } 1435 1436 const DynamicRefTable* dynamicRefTable = 1437 am->getResources().getDynamicRefTableForCookie(assetCookie); 1438 ResXMLTree* block = new ResXMLTree(dynamicRefTable); 1439 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true); 1440 a->close(); 1441 delete a; 1442 1443 if (err != NO_ERROR) { 1444 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file"); 1445 return 0; 1446 } 1447 1448 return reinterpret_cast<jlong>(block); 1449} 1450 1451static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz, 1452 jint arrayResId) 1453{ 1454 AssetManager* am = assetManagerForJavaObject(env, clazz); 1455 if (am == NULL) { 1456 return NULL; 1457 } 1458 const ResTable& res(am->getResources()); 1459 1460 const ResTable::bag_entry* startOfBag; 1461 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1462 if (N < 0) { 1463 return NULL; 1464 } 1465 1466 jintArray array = env->NewIntArray(N * 2); 1467 if (array == NULL) { 1468 res.unlockBag(startOfBag); 1469 return NULL; 1470 } 1471 1472 Res_value value; 1473 const ResTable::bag_entry* bag = startOfBag; 1474 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) { 1475 jint stringIndex = -1; 1476 jint stringBlock = 0; 1477 value = bag->map.value; 1478 1479 // Take care of resolving the found resource to its final value. 1480 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL); 1481 if (value.dataType == Res_value::TYPE_STRING) { 1482 stringIndex = value.data; 1483 } 1484 1485 if (kThrowOnBadId) { 1486 if (stringBlock == BAD_INDEX) { 1487 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1488 return array; 1489 } 1490 } 1491 1492 //todo: It might be faster to allocate a C array to contain 1493 // the blocknums and indices, put them in there and then 1494 // do just one SetIntArrayRegion() 1495 env->SetIntArrayRegion(array, j, 1, &stringBlock); 1496 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex); 1497 j = j + 2; 1498 } 1499 res.unlockBag(startOfBag); 1500 return array; 1501} 1502 1503static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz, 1504 jint arrayResId) 1505{ 1506 AssetManager* am = assetManagerForJavaObject(env, clazz); 1507 if (am == NULL) { 1508 return NULL; 1509 } 1510 const ResTable& res(am->getResources()); 1511 1512 const ResTable::bag_entry* startOfBag; 1513 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1514 if (N < 0) { 1515 return NULL; 1516 } 1517 1518 jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL); 1519 if (env->ExceptionCheck()) { 1520 res.unlockBag(startOfBag); 1521 return NULL; 1522 } 1523 1524 Res_value value; 1525 const ResTable::bag_entry* bag = startOfBag; 1526 size_t strLen = 0; 1527 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1528 value = bag->map.value; 1529 jstring str = NULL; 1530 1531 // Take care of resolving the found resource to its final value. 1532 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1533 if (kThrowOnBadId) { 1534 if (block == BAD_INDEX) { 1535 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1536 return array; 1537 } 1538 } 1539 if (value.dataType == Res_value::TYPE_STRING) { 1540 const ResStringPool* pool = res.getTableStringBlock(block); 1541 const char* str8 = pool->string8At(value.data, &strLen); 1542 if (str8 != NULL) { 1543 str = env->NewStringUTF(str8); 1544 } else { 1545 const char16_t* str16 = pool->stringAt(value.data, &strLen); 1546 str = env->NewString(reinterpret_cast<const jchar*>(str16), 1547 strLen); 1548 } 1549 1550 // If one of our NewString{UTF} calls failed due to memory, an 1551 // exception will be pending. 1552 if (env->ExceptionCheck()) { 1553 res.unlockBag(startOfBag); 1554 return NULL; 1555 } 1556 1557 env->SetObjectArrayElement(array, i, str); 1558 1559 // str is not NULL at that point, otherwise ExceptionCheck would have been true. 1560 // If we have a large amount of strings in our array, we might 1561 // overflow the local reference table of the VM. 1562 env->DeleteLocalRef(str); 1563 } 1564 } 1565 res.unlockBag(startOfBag); 1566 return array; 1567} 1568 1569static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz, 1570 jint arrayResId) 1571{ 1572 AssetManager* am = assetManagerForJavaObject(env, clazz); 1573 if (am == NULL) { 1574 return NULL; 1575 } 1576 const ResTable& res(am->getResources()); 1577 1578 const ResTable::bag_entry* startOfBag; 1579 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1580 if (N < 0) { 1581 return NULL; 1582 } 1583 1584 jintArray array = env->NewIntArray(N); 1585 if (array == NULL) { 1586 res.unlockBag(startOfBag); 1587 return NULL; 1588 } 1589 1590 Res_value value; 1591 const ResTable::bag_entry* bag = startOfBag; 1592 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1593 value = bag->map.value; 1594 1595 // Take care of resolving the found resource to its final value. 1596 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1597 if (kThrowOnBadId) { 1598 if (block == BAD_INDEX) { 1599 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1600 return array; 1601 } 1602 } 1603 if (value.dataType >= Res_value::TYPE_FIRST_INT 1604 && value.dataType <= Res_value::TYPE_LAST_INT) { 1605 int intVal = value.data; 1606 env->SetIntArrayRegion(array, i, 1, &intVal); 1607 } 1608 } 1609 res.unlockBag(startOfBag); 1610 return array; 1611} 1612 1613static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz, 1614 jint styleId) 1615{ 1616 AssetManager* am = assetManagerForJavaObject(env, clazz); 1617 if (am == NULL) { 1618 return NULL; 1619 } 1620 const ResTable& res(am->getResources()); 1621 1622 const ResTable::bag_entry* startOfBag; 1623 const ssize_t N = res.lockBag(styleId, &startOfBag); 1624 if (N < 0) { 1625 return NULL; 1626 } 1627 1628 jintArray array = env->NewIntArray(N); 1629 if (array == NULL) { 1630 res.unlockBag(startOfBag); 1631 return NULL; 1632 } 1633 1634 const ResTable::bag_entry* bag = startOfBag; 1635 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1636 int resourceId = bag->map.name.ident; 1637 env->SetIntArrayRegion(array, i, 1, &resourceId); 1638 } 1639 res.unlockBag(startOfBag); 1640 return array; 1641} 1642 1643static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem) 1644{ 1645 if (isSystem) { 1646 verifySystemIdmaps(); 1647 } 1648 AssetManager* am = new AssetManager(); 1649 if (am == NULL) { 1650 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1651 return; 1652 } 1653 1654 am->addDefaultAssets(); 1655 1656 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz); 1657 env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am)); 1658} 1659 1660static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz) 1661{ 1662 AssetManager* am = (AssetManager*) 1663 (env->GetLongField(clazz, gAssetManagerOffsets.mObject)); 1664 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz); 1665 if (am != NULL) { 1666 delete am; 1667 env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0); 1668 } 1669} 1670 1671static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz) 1672{ 1673 return Asset::getGlobalCount(); 1674} 1675 1676static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz) 1677{ 1678 String8 alloc = Asset::getAssetAllocations(); 1679 if (alloc.length() <= 0) { 1680 return NULL; 1681 } 1682 1683 jstring str = env->NewStringUTF(alloc.string()); 1684 return str; 1685} 1686 1687static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz) 1688{ 1689 return AssetManager::getGlobalCount(); 1690} 1691 1692// ---------------------------------------------------------------------------- 1693 1694/* 1695 * JNI registration. 1696 */ 1697static const JNINativeMethod gAssetManagerMethods[] = { 1698 /* name, signature, funcPtr */ 1699 1700 // Basic asset stuff. 1701 { "openAsset", "(Ljava/lang/String;I)J", 1702 (void*) android_content_AssetManager_openAsset }, 1703 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1704 (void*) android_content_AssetManager_openAssetFd }, 1705 { "openNonAssetNative", "(ILjava/lang/String;I)J", 1706 (void*) android_content_AssetManager_openNonAssetNative }, 1707 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1708 (void*) android_content_AssetManager_openNonAssetFdNative }, 1709 { "list", "(Ljava/lang/String;)[Ljava/lang/String;", 1710 (void*) android_content_AssetManager_list }, 1711 { "destroyAsset", "(J)V", 1712 (void*) android_content_AssetManager_destroyAsset }, 1713 { "readAssetChar", "(J)I", 1714 (void*) android_content_AssetManager_readAssetChar }, 1715 { "readAsset", "(J[BII)I", 1716 (void*) android_content_AssetManager_readAsset }, 1717 { "seekAsset", "(JJI)J", 1718 (void*) android_content_AssetManager_seekAsset }, 1719 // @FastNative 1720 { "getAssetLength", "(J)J", 1721 (void*) android_content_AssetManager_getAssetLength }, 1722 // @FastNative 1723 { "getAssetRemainingLength", "(J)J", 1724 (void*) android_content_AssetManager_getAssetRemainingLength }, 1725 { "addAssetPathNative", "(Ljava/lang/String;Z)I", 1726 (void*) android_content_AssetManager_addAssetPath }, 1727 { "addOverlayPathNative", "(Ljava/lang/String;)I", 1728 (void*) android_content_AssetManager_addOverlayPath }, 1729 { "isUpToDate", "()Z", 1730 (void*) android_content_AssetManager_isUpToDate }, 1731 1732 // Resources. 1733 { "getLocales", "()[Ljava/lang/String;", 1734 (void*) android_content_AssetManager_getLocales }, 1735 { "getNonSystemLocales", "()[Ljava/lang/String;", 1736 (void*) android_content_AssetManager_getNonSystemLocales }, 1737 { "getSizeConfigurations", "()[Landroid/content/res/Configuration;", 1738 (void*) android_content_AssetManager_getSizeConfigurations }, 1739 // @FastNative 1740 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V", 1741 (void*) android_content_AssetManager_setConfiguration }, 1742 // @FastNative 1743 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", 1744 (void*) android_content_AssetManager_getResourceIdentifier }, 1745 // @FastNative 1746 { "getResourceName","(I)Ljava/lang/String;", 1747 (void*) android_content_AssetManager_getResourceName }, 1748 // @FastNative 1749 { "getResourcePackageName","(I)Ljava/lang/String;", 1750 (void*) android_content_AssetManager_getResourcePackageName }, 1751 // @FastNative 1752 { "getResourceTypeName","(I)Ljava/lang/String;", 1753 (void*) android_content_AssetManager_getResourceTypeName }, 1754 // @FastNative 1755 { "getResourceEntryName","(I)Ljava/lang/String;", 1756 (void*) android_content_AssetManager_getResourceEntryName }, 1757 // @FastNative 1758 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I", 1759 (void*) android_content_AssetManager_loadResourceValue }, 1760 // @FastNative 1761 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I", 1762 (void*) android_content_AssetManager_loadResourceBagValue }, 1763 // @FastNative 1764 { "getStringBlockCount","()I", 1765 (void*) android_content_AssetManager_getStringBlockCount }, 1766 // @FastNative 1767 { "getNativeStringBlock","(I)J", 1768 (void*) android_content_AssetManager_getNativeStringBlock }, 1769 { "getCookieName","(I)Ljava/lang/String;", 1770 (void*) android_content_AssetManager_getCookieName }, 1771 { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;", 1772 (void*) android_content_AssetManager_getAssignedPackageIdentifiers }, 1773 1774 // Themes. 1775 { "newTheme", "()J", 1776 (void*) android_content_AssetManager_newTheme }, 1777 { "deleteTheme", "(J)V", 1778 (void*) android_content_AssetManager_deleteTheme }, 1779 { "applyThemeStyle", "(JIZ)V", 1780 (void*) android_content_AssetManager_applyThemeStyle }, 1781 { "copyTheme", "(JJ)V", 1782 (void*) android_content_AssetManager_copyTheme }, 1783 { "clearTheme", "(J)V", 1784 (void*) android_content_AssetManager_clearTheme }, 1785 // @FastNative 1786 { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I", 1787 (void*) android_content_AssetManager_loadThemeAttributeValue }, 1788 // @FastNative 1789 { "getThemeChangingConfigurations", "(J)I", 1790 (void*) android_content_AssetManager_getThemeChangingConfigurations }, 1791 { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V", 1792 (void*) android_content_AssetManager_dumpTheme }, 1793 // @FastNative 1794 { "applyStyle","(JIIJ[I[I[I)Z", 1795 (void*) android_content_AssetManager_applyStyle }, 1796 // @FastNative 1797 { "resolveAttrs","(JII[I[I[I[I)Z", 1798 (void*) android_content_AssetManager_resolveAttrs }, 1799 // @FastNative 1800 { "retrieveAttributes","(J[I[I[I)Z", 1801 (void*) android_content_AssetManager_retrieveAttributes }, 1802 // @FastNative 1803 { "getArraySize","(I)I", 1804 (void*) android_content_AssetManager_getArraySize }, 1805 // @FastNative 1806 { "retrieveArray","(I[I)I", 1807 (void*) android_content_AssetManager_retrieveArray }, 1808 1809 // XML files. 1810 { "openXmlAssetNative", "(ILjava/lang/String;)J", 1811 (void*) android_content_AssetManager_openXmlAssetNative }, 1812 1813 // Arrays. 1814 { "getArrayStringResource","(I)[Ljava/lang/String;", 1815 (void*) android_content_AssetManager_getArrayStringResource }, 1816 // @FastNative 1817 { "getArrayStringInfo","(I)[I", 1818 (void*) android_content_AssetManager_getArrayStringInfo }, 1819 // @FastNative 1820 { "getArrayIntResource","(I)[I", 1821 (void*) android_content_AssetManager_getArrayIntResource }, 1822 // @FastNative 1823 { "getStyleAttributes","(I)[I", 1824 (void*) android_content_AssetManager_getStyleAttributes }, 1825 1826 // Bookkeeping. 1827 { "init", "(Z)V", 1828 (void*) android_content_AssetManager_init }, 1829 { "destroy", "()V", 1830 (void*) android_content_AssetManager_destroy }, 1831 { "getGlobalAssetCount", "()I", 1832 (void*) android_content_AssetManager_getGlobalAssetCount }, 1833 { "getAssetAllocations", "()Ljava/lang/String;", 1834 (void*) android_content_AssetManager_getAssetAllocations }, 1835 { "getGlobalAssetManagerCount", "()I", 1836 (void*) android_content_AssetManager_getGlobalAssetManagerCount }, 1837}; 1838 1839int register_android_content_AssetManager(JNIEnv* env) 1840{ 1841 jclass typedValue = FindClassOrDie(env, "android/util/TypedValue"); 1842 gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I"); 1843 gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I"); 1844 gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string", 1845 "Ljava/lang/CharSequence;"); 1846 gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I"); 1847 gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I"); 1848 gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue, 1849 "changingConfigurations", "I"); 1850 gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I"); 1851 1852 jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor"); 1853 gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd", 1854 "Landroid/os/ParcelFileDescriptor;"); 1855 gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J"); 1856 gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J"); 1857 1858 jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager"); 1859 gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J"); 1860 1861 jclass stringClass = FindClassOrDie(env, "java/lang/String"); 1862 g_stringClass = MakeGlobalRefOrDie(env, stringClass); 1863 1864 jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray"); 1865 gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass); 1866 gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, 1867 "<init>", "()V"); 1868 gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", 1869 "(ILjava/lang/Object;)V"); 1870 1871 jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration"); 1872 gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass); 1873 gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, 1874 "<init>", "()V"); 1875 gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass, 1876 "smallestScreenWidthDp", "I"); 1877 gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass, 1878 "screenWidthDp", "I"); 1879 gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass, 1880 "screenHeightDp", "I"); 1881 1882 return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods, 1883 NELEM(gAssetManagerMethods)); 1884} 1885 1886}; // namespace android 1887