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