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