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