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