1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.res; 18 19 import android.annotation.AnyRes; 20 import android.annotation.ArrayRes; 21 import android.annotation.AttrRes; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.annotation.StringRes; 25 import android.annotation.StyleRes; 26 import android.annotation.TestApi; 27 import android.compat.annotation.UnsupportedAppUsage; 28 import android.content.pm.ActivityInfo; 29 import android.content.res.Configuration.NativeConfig; 30 import android.os.ParcelFileDescriptor; 31 import android.util.ArraySet; 32 import android.util.Log; 33 import android.util.SparseArray; 34 import android.util.TypedValue; 35 36 import com.android.internal.annotations.GuardedBy; 37 import com.android.internal.util.Preconditions; 38 39 import libcore.io.IoUtils; 40 41 import java.io.BufferedReader; 42 import java.io.FileInputStream; 43 import java.io.FileNotFoundException; 44 import java.io.IOException; 45 import java.io.InputStream; 46 import java.io.InputStreamReader; 47 import java.nio.channels.FileLock; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.Map; 52 53 /** 54 * Provides access to an application's raw asset files; see {@link Resources} 55 * for the way most applications will want to retrieve their resource data. 56 * This class presents a lower-level API that allows you to open and read raw 57 * files that have been bundled with the application as a simple stream of 58 * bytes. 59 */ 60 public final class AssetManager implements AutoCloseable { 61 private static final String TAG = "AssetManager"; 62 private static final boolean DEBUG_REFS = false; 63 private static final boolean FEATURE_FLAG_IDMAP2 = true; 64 65 private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; 66 67 private static final Object sSync = new Object(); 68 69 private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0]; 70 71 // Not private for LayoutLib's BridgeAssetManager. 72 @UnsupportedAppUsage 73 @GuardedBy("sSync") static AssetManager sSystem = null; 74 75 @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0]; 76 @GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet; 77 78 /** 79 * Mode for {@link #open(String, int)}: no specific information about how 80 * data will be accessed. 81 */ 82 public static final int ACCESS_UNKNOWN = 0; 83 /** 84 * Mode for {@link #open(String, int)}: Read chunks, and seek forward and 85 * backward. 86 */ 87 public static final int ACCESS_RANDOM = 1; 88 /** 89 * Mode for {@link #open(String, int)}: Read sequentially, with an 90 * occasional forward seek. 91 */ 92 public static final int ACCESS_STREAMING = 2; 93 /** 94 * Mode for {@link #open(String, int)}: Attempt to load contents into 95 * memory, for fast small reads. 96 */ 97 public static final int ACCESS_BUFFER = 3; 98 99 @GuardedBy("this") private final TypedValue mValue = new TypedValue(); 100 @GuardedBy("this") private final long[] mOffsets = new long[2]; 101 102 // Pointer to native implementation, stuffed inside a long. 103 @UnsupportedAppUsage 104 @GuardedBy("this") private long mObject; 105 106 // The loaded asset paths. 107 @GuardedBy("this") private ApkAssets[] mApkAssets; 108 109 // Debug/reference counting implementation. 110 @GuardedBy("this") private boolean mOpen = true; 111 @GuardedBy("this") private int mNumRefs = 1; 112 @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks; 113 114 /** 115 * A Builder class that helps create an AssetManager with only a single invocation of 116 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. Without using this builder, 117 * AssetManager must ensure there are system ApkAssets loaded at all times, which when combined 118 * with the user's call to add additional ApkAssets, results in multiple calls to 119 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. 120 * @hide 121 */ 122 public static class Builder { 123 private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>(); 124 addApkAssets(ApkAssets apkAssets)125 public Builder addApkAssets(ApkAssets apkAssets) { 126 mUserApkAssets.add(apkAssets); 127 return this; 128 } 129 build()130 public AssetManager build() { 131 // Retrieving the system ApkAssets forces their creation as well. 132 final ApkAssets[] systemApkAssets = getSystem().getApkAssets(); 133 134 final int totalApkAssetCount = systemApkAssets.length + mUserApkAssets.size(); 135 final ApkAssets[] apkAssets = new ApkAssets[totalApkAssetCount]; 136 137 System.arraycopy(systemApkAssets, 0, apkAssets, 0, systemApkAssets.length); 138 139 final int userApkAssetCount = mUserApkAssets.size(); 140 for (int i = 0; i < userApkAssetCount; i++) { 141 apkAssets[i + systemApkAssets.length] = mUserApkAssets.get(i); 142 } 143 144 // Calling this constructor prevents creation of system ApkAssets, which we took care 145 // of in this Builder. 146 final AssetManager assetManager = new AssetManager(false /*sentinel*/); 147 assetManager.mApkAssets = apkAssets; 148 AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets, 149 false /*invalidateCaches*/); 150 return assetManager; 151 } 152 } 153 154 /** 155 * Create a new AssetManager containing only the basic system assets. 156 * Applications will not generally use this method, instead retrieving the 157 * appropriate asset manager with {@link Resources#getAssets}. Not for 158 * use by applications. 159 * @hide 160 */ 161 @UnsupportedAppUsage AssetManager()162 public AssetManager() { 163 final ApkAssets[] assets; 164 synchronized (sSync) { 165 createSystemAssetsInZygoteLocked(); 166 assets = sSystemApkAssets; 167 } 168 169 mObject = nativeCreate(); 170 if (DEBUG_REFS) { 171 mNumRefs = 0; 172 incRefsLocked(hashCode()); 173 } 174 175 // Always set the framework resources. 176 setApkAssets(assets, false /*invalidateCaches*/); 177 } 178 179 /** 180 * Private constructor that doesn't call ensureSystemAssets. 181 * Used for the creation of system assets. 182 */ 183 @SuppressWarnings("unused") AssetManager(boolean sentinel)184 private AssetManager(boolean sentinel) { 185 mObject = nativeCreate(); 186 if (DEBUG_REFS) { 187 mNumRefs = 0; 188 incRefsLocked(hashCode()); 189 } 190 } 191 192 /** 193 * This must be called from Zygote so that system assets are shared by all applications. 194 */ 195 @GuardedBy("sSync") createSystemAssetsInZygoteLocked()196 private static void createSystemAssetsInZygoteLocked() { 197 if (sSystem != null) { 198 return; 199 } 200 201 202 try { 203 final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); 204 apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/)); 205 if (FEATURE_FLAG_IDMAP2) { 206 final String[] systemIdmapPaths = 207 nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); 208 if (systemIdmapPaths != null) { 209 for (String idmapPath : systemIdmapPaths) { 210 apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); 211 } 212 } else { 213 Log.w(TAG, "'idmap2 --scan' failed: no static=\"true\" overlays targeting " 214 + "\"android\" will be loaded"); 215 } 216 } else { 217 nativeVerifySystemIdmaps(); 218 loadStaticRuntimeOverlays(apkAssets); 219 } 220 221 sSystemApkAssetsSet = new ArraySet<>(apkAssets); 222 sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]); 223 sSystem = new AssetManager(true /*sentinel*/); 224 sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/); 225 } catch (IOException e) { 226 throw new IllegalStateException("Failed to create system AssetManager", e); 227 } 228 } 229 230 /** 231 * Loads the static runtime overlays declared in /data/resource-cache/overlays.list. 232 * Throws an exception if the file is corrupt or if loading the APKs referenced by the file 233 * fails. Returns quietly if the overlays.list file doesn't exist. 234 * @param outApkAssets The list to fill with the loaded ApkAssets. 235 */ loadStaticRuntimeOverlays(ArrayList<ApkAssets> outApkAssets)236 private static void loadStaticRuntimeOverlays(ArrayList<ApkAssets> outApkAssets) 237 throws IOException { 238 final FileInputStream fis; 239 try { 240 fis = new FileInputStream("/data/resource-cache/overlays.list"); 241 } catch (FileNotFoundException e) { 242 // We might not have any overlays, this is fine. We catch here since ApkAssets 243 // loading can also fail with the same exception, which we would want to propagate. 244 Log.i(TAG, "no overlays.list file found"); 245 return; 246 } 247 248 try { 249 // Acquire a lock so that any idmap scanning doesn't impact the current set. 250 // The order of this try-with-resources block matters. We must release the lock, and 251 // then close the file streams when exiting the block. 252 try (final BufferedReader br = new BufferedReader(new InputStreamReader(fis)); 253 final FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE, true /*shared*/)) { 254 for (String line; (line = br.readLine()) != null; ) { 255 final String idmapPath = line.split(" ")[1]; 256 outApkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/)); 257 } 258 } 259 } finally { 260 // When BufferedReader is closed above, FileInputStream is closed as well. But let's be 261 // paranoid. 262 IoUtils.closeQuietly(fis); 263 } 264 } 265 266 /** 267 * Return a global shared asset manager that provides access to only 268 * system assets (no application assets). 269 * @hide 270 */ 271 @UnsupportedAppUsage getSystem()272 public static AssetManager getSystem() { 273 synchronized (sSync) { 274 createSystemAssetsInZygoteLocked(); 275 return sSystem; 276 } 277 } 278 279 /** 280 * Close this asset manager. 281 */ 282 @Override close()283 public void close() { 284 synchronized (this) { 285 if (!mOpen) { 286 return; 287 } 288 289 mOpen = false; 290 decRefsLocked(hashCode()); 291 } 292 } 293 294 /** 295 * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)} 296 * family of methods. 297 * 298 * @param apkAssets The new set of paths. 299 * @param invalidateCaches Whether to invalidate any caches. This should almost always be true. 300 * Set this to false if you are appending new resources 301 * (not new configurations). 302 * @hide 303 */ setApkAssets(@onNull ApkAssets[] apkAssets, boolean invalidateCaches)304 public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) { 305 Preconditions.checkNotNull(apkAssets, "apkAssets"); 306 307 ApkAssets[] newApkAssets = new ApkAssets[sSystemApkAssets.length + apkAssets.length]; 308 309 // Copy the system assets first. 310 System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length); 311 312 // Copy the given ApkAssets if they are not already in the system list. 313 int newLength = sSystemApkAssets.length; 314 for (ApkAssets apkAsset : apkAssets) { 315 if (!sSystemApkAssetsSet.contains(apkAsset)) { 316 newApkAssets[newLength++] = apkAsset; 317 } 318 } 319 320 // Truncate if necessary. 321 if (newLength != newApkAssets.length) { 322 newApkAssets = Arrays.copyOf(newApkAssets, newLength); 323 } 324 325 synchronized (this) { 326 ensureOpenLocked(); 327 mApkAssets = newApkAssets; 328 nativeSetApkAssets(mObject, mApkAssets, invalidateCaches); 329 if (invalidateCaches) { 330 // Invalidate all caches. 331 invalidateCachesLocked(-1); 332 } 333 } 334 } 335 336 /** 337 * Invalidates the caches in this AssetManager according to the bitmask `diff`. 338 * 339 * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}. 340 * @see ActivityInfo.Config 341 */ invalidateCachesLocked(int diff)342 private void invalidateCachesLocked(int diff) { 343 // TODO(adamlesinski): Currently there are no caches to invalidate in Java code. 344 } 345 346 /** 347 * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this 348 * returns a 0-length array. 349 * @hide 350 */ 351 @UnsupportedAppUsage getApkAssets()352 public @NonNull ApkAssets[] getApkAssets() { 353 synchronized (this) { 354 if (mOpen) { 355 return mApkAssets; 356 } 357 } 358 return sEmptyApkAssets; 359 } 360 361 /** @hide */ 362 @TestApi getApkPaths()363 public @NonNull String[] getApkPaths() { 364 synchronized (this) { 365 if (mOpen) { 366 String[] paths = new String[mApkAssets.length]; 367 final int count = mApkAssets.length; 368 for (int i = 0; i < count; i++) { 369 paths[i] = mApkAssets[i].getAssetPath(); 370 } 371 return paths; 372 } 373 } 374 return new String[0]; 375 } 376 377 /** 378 * Returns a cookie for use with the other APIs of AssetManager. 379 * @return 0 if the path was not found, otherwise a positive integer cookie representing 380 * this path in the AssetManager. 381 * @hide 382 */ findCookieForPath(@onNull String path)383 public int findCookieForPath(@NonNull String path) { 384 Preconditions.checkNotNull(path, "path"); 385 synchronized (this) { 386 ensureValidLocked(); 387 final int count = mApkAssets.length; 388 for (int i = 0; i < count; i++) { 389 if (path.equals(mApkAssets[i].getAssetPath())) { 390 return i + 1; 391 } 392 } 393 } 394 return 0; 395 } 396 397 /** 398 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 399 * @hide 400 */ 401 @Deprecated 402 @UnsupportedAppUsage addAssetPath(String path)403 public int addAssetPath(String path) { 404 return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/); 405 } 406 407 /** 408 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 409 * @hide 410 */ 411 @Deprecated 412 @UnsupportedAppUsage addAssetPathAsSharedLibrary(String path)413 public int addAssetPathAsSharedLibrary(String path) { 414 return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/); 415 } 416 417 /** 418 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 419 * @hide 420 */ 421 @Deprecated 422 @UnsupportedAppUsage addOverlayPath(String path)423 public int addOverlayPath(String path) { 424 return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/); 425 } 426 addAssetPathInternal(String path, boolean overlay, boolean appAsLib)427 private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) { 428 Preconditions.checkNotNull(path, "path"); 429 synchronized (this) { 430 ensureOpenLocked(); 431 final int count = mApkAssets.length; 432 433 // See if we already have it loaded. 434 for (int i = 0; i < count; i++) { 435 if (mApkAssets[i].getAssetPath().equals(path)) { 436 return i + 1; 437 } 438 } 439 440 final ApkAssets assets; 441 try { 442 if (overlay) { 443 // TODO(b/70343104): This hardcoded path will be removed once 444 // addAssetPathInternal is deleted. 445 final String idmapPath = "/data/resource-cache/" 446 + path.substring(1).replace('/', '@') 447 + "@idmap"; 448 assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/); 449 } else { 450 assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib); 451 } 452 } catch (IOException e) { 453 return 0; 454 } 455 456 mApkAssets = Arrays.copyOf(mApkAssets, count + 1); 457 mApkAssets[count] = assets; 458 nativeSetApkAssets(mObject, mApkAssets, true); 459 invalidateCachesLocked(-1); 460 return count + 1; 461 } 462 } 463 464 /** 465 * Ensures that the native implementation has not been destroyed. 466 * The AssetManager may have been closed, but references to it still exist 467 * and therefore the native implementation is not destroyed. 468 */ 469 @GuardedBy("this") ensureValidLocked()470 private void ensureValidLocked() { 471 if (mObject == 0) { 472 throw new RuntimeException("AssetManager has been destroyed"); 473 } 474 } 475 476 /** 477 * Ensures that the AssetManager has not been explicitly closed. If this method passes, 478 * then this implies that ensureValidLocked() also passes. 479 */ 480 @GuardedBy("this") ensureOpenLocked()481 private void ensureOpenLocked() { 482 // If mOpen is true, this implies that mObject != 0. 483 if (!mOpen) { 484 throw new RuntimeException("AssetManager has been closed"); 485 } 486 } 487 488 /** 489 * Populates {@code outValue} with the data associated a particular 490 * resource identifier for the current configuration. 491 * 492 * @param resId the resource identifier to load 493 * @param densityDpi the density bucket for which to load the resource 494 * @param outValue the typed value in which to put the data 495 * @param resolveRefs {@code true} to resolve references, {@code false} 496 * to leave them unresolved 497 * @return {@code true} if the data was loaded into {@code outValue}, 498 * {@code false} otherwise 499 */ 500 @UnsupportedAppUsage getResourceValue(@nyRes int resId, int densityDpi, @NonNull TypedValue outValue, boolean resolveRefs)501 boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue, 502 boolean resolveRefs) { 503 Preconditions.checkNotNull(outValue, "outValue"); 504 synchronized (this) { 505 ensureValidLocked(); 506 final int cookie = nativeGetResourceValue( 507 mObject, resId, (short) densityDpi, outValue, resolveRefs); 508 if (cookie <= 0) { 509 return false; 510 } 511 512 // Convert the changing configurations flags populated by native code. 513 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 514 outValue.changingConfigurations); 515 516 if (outValue.type == TypedValue.TYPE_STRING) { 517 outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data); 518 } 519 return true; 520 } 521 } 522 523 /** 524 * Retrieves the string value associated with a particular resource 525 * identifier for the current configuration. 526 * 527 * @param resId the resource identifier to load 528 * @return the string value, or {@code null} 529 */ 530 @UnsupportedAppUsage getResourceText(@tringRes int resId)531 @Nullable CharSequence getResourceText(@StringRes int resId) { 532 synchronized (this) { 533 final TypedValue outValue = mValue; 534 if (getResourceValue(resId, 0, outValue, true)) { 535 return outValue.coerceToString(); 536 } 537 return null; 538 } 539 } 540 541 /** 542 * Retrieves the string value associated with a particular resource 543 * identifier for the current configuration. 544 * 545 * @param resId the resource identifier to load 546 * @param bagEntryId the index into the bag to load 547 * @return the string value, or {@code null} 548 */ 549 @UnsupportedAppUsage getResourceBagText(@tringRes int resId, int bagEntryId)550 @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) { 551 synchronized (this) { 552 ensureValidLocked(); 553 final TypedValue outValue = mValue; 554 final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue); 555 if (cookie <= 0) { 556 return null; 557 } 558 559 // Convert the changing configurations flags populated by native code. 560 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 561 outValue.changingConfigurations); 562 563 if (outValue.type == TypedValue.TYPE_STRING) { 564 return mApkAssets[cookie - 1].getStringFromPool(outValue.data); 565 } 566 return outValue.coerceToString(); 567 } 568 } 569 getResourceArraySize(@rrayRes int resId)570 int getResourceArraySize(@ArrayRes int resId) { 571 synchronized (this) { 572 ensureValidLocked(); 573 return nativeGetResourceArraySize(mObject, resId); 574 } 575 } 576 577 /** 578 * Populates `outData` with array elements of `resId`. `outData` is normally 579 * used with 580 * {@link TypedArray}. 581 * 582 * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES} 583 * long, 584 * with the indices of the data representing the type, value, asset cookie, 585 * resource ID, 586 * configuration change mask, and density of the element. 587 * 588 * @param resId The resource ID of an array resource. 589 * @param outData The array to populate with data. 590 * @return The length of the array. 591 * 592 * @see TypedArray#STYLE_TYPE 593 * @see TypedArray#STYLE_DATA 594 * @see TypedArray#STYLE_ASSET_COOKIE 595 * @see TypedArray#STYLE_RESOURCE_ID 596 * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS 597 * @see TypedArray#STYLE_DENSITY 598 */ getResourceArray(@rrayRes int resId, @NonNull int[] outData)599 int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) { 600 Preconditions.checkNotNull(outData, "outData"); 601 synchronized (this) { 602 ensureValidLocked(); 603 return nativeGetResourceArray(mObject, resId, outData); 604 } 605 } 606 607 /** 608 * Retrieves the string array associated with a particular resource 609 * identifier for the current configuration. 610 * 611 * @param resId the resource identifier of the string array 612 * @return the string array, or {@code null} 613 */ getResourceStringArray(@rrayRes int resId)614 @Nullable String[] getResourceStringArray(@ArrayRes int resId) { 615 synchronized (this) { 616 ensureValidLocked(); 617 return nativeGetResourceStringArray(mObject, resId); 618 } 619 } 620 621 /** 622 * Retrieve the text array associated with a particular resource 623 * identifier. 624 * 625 * @param resId the resource id of the string array 626 */ getResourceTextArray(@rrayRes int resId)627 @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) { 628 synchronized (this) { 629 ensureValidLocked(); 630 final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId); 631 if (rawInfoArray == null) { 632 return null; 633 } 634 635 final int rawInfoArrayLen = rawInfoArray.length; 636 final int infoArrayLen = rawInfoArrayLen / 2; 637 final CharSequence[] retArray = new CharSequence[infoArrayLen]; 638 for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) { 639 int cookie = rawInfoArray[i]; 640 int index = rawInfoArray[i + 1]; 641 retArray[j] = (index >= 0 && cookie > 0) 642 ? mApkAssets[cookie - 1].getStringFromPool(index) : null; 643 } 644 return retArray; 645 } 646 } 647 getResourceIntArray(@rrayRes int resId)648 @Nullable int[] getResourceIntArray(@ArrayRes int resId) { 649 synchronized (this) { 650 ensureValidLocked(); 651 return nativeGetResourceIntArray(mObject, resId); 652 } 653 } 654 655 /** 656 * Get the attributes for a style resource. These are the <item> 657 * elements in 658 * a <style> resource. 659 * @param resId The resource ID of the style 660 * @return An array of attribute IDs. 661 */ getStyleAttributes(@tyleRes int resId)662 @AttrRes int[] getStyleAttributes(@StyleRes int resId) { 663 synchronized (this) { 664 ensureValidLocked(); 665 return nativeGetStyleAttributes(mObject, resId); 666 } 667 } 668 669 /** 670 * Populates {@code outValue} with the data associated with a particular 671 * resource identifier for the current configuration. Resolves theme 672 * attributes against the specified theme. 673 * 674 * @param theme the native pointer of the theme 675 * @param resId the resource identifier to load 676 * @param outValue the typed value in which to put the data 677 * @param resolveRefs {@code true} to resolve references, {@code false} 678 * to leave them unresolved 679 * @return {@code true} if the data was loaded into {@code outValue}, 680 * {@code false} otherwise 681 */ getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, boolean resolveRefs)682 boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, 683 boolean resolveRefs) { 684 Preconditions.checkNotNull(outValue, "outValue"); 685 synchronized (this) { 686 ensureValidLocked(); 687 final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue, 688 resolveRefs); 689 if (cookie <= 0) { 690 return false; 691 } 692 693 // Convert the changing configurations flags populated by native code. 694 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 695 outValue.changingConfigurations); 696 697 if (outValue.type == TypedValue.TYPE_STRING) { 698 outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data); 699 } 700 return true; 701 } 702 } 703 dumpTheme(long theme, int priority, String tag, String prefix)704 void dumpTheme(long theme, int priority, String tag, String prefix) { 705 synchronized (this) { 706 ensureValidLocked(); 707 nativeThemeDump(mObject, theme, priority, tag, prefix); 708 } 709 } 710 711 @UnsupportedAppUsage getResourceName(@nyRes int resId)712 @Nullable String getResourceName(@AnyRes int resId) { 713 synchronized (this) { 714 ensureValidLocked(); 715 return nativeGetResourceName(mObject, resId); 716 } 717 } 718 719 @UnsupportedAppUsage getResourcePackageName(@nyRes int resId)720 @Nullable String getResourcePackageName(@AnyRes int resId) { 721 synchronized (this) { 722 ensureValidLocked(); 723 return nativeGetResourcePackageName(mObject, resId); 724 } 725 } 726 727 @UnsupportedAppUsage getResourceTypeName(@nyRes int resId)728 @Nullable String getResourceTypeName(@AnyRes int resId) { 729 synchronized (this) { 730 ensureValidLocked(); 731 return nativeGetResourceTypeName(mObject, resId); 732 } 733 } 734 735 @UnsupportedAppUsage getResourceEntryName(@nyRes int resId)736 @Nullable String getResourceEntryName(@AnyRes int resId) { 737 synchronized (this) { 738 ensureValidLocked(); 739 return nativeGetResourceEntryName(mObject, resId); 740 } 741 } 742 743 @UnsupportedAppUsage getResourceIdentifier(@onNull String name, @Nullable String defType, @Nullable String defPackage)744 @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType, 745 @Nullable String defPackage) { 746 synchronized (this) { 747 ensureValidLocked(); 748 // name is checked in JNI. 749 return nativeGetResourceIdentifier(mObject, name, defType, defPackage); 750 } 751 } 752 753 /** 754 * Enable resource resolution logging to track the steps taken to resolve the last resource 755 * entry retrieved. Stores the configuration and package names for each step. 756 * 757 * Default disabled. 758 * 759 * @param enabled Boolean indicating whether to enable or disable logging. 760 * 761 * @hide 762 */ setResourceResolutionLoggingEnabled(boolean enabled)763 public void setResourceResolutionLoggingEnabled(boolean enabled) { 764 synchronized (this) { 765 ensureValidLocked(); 766 nativeSetResourceResolutionLoggingEnabled(mObject, enabled); 767 } 768 } 769 770 /** 771 * Retrieve the last resource resolution path logged. 772 * 773 * @return Formatted string containing last resource ID/name and steps taken to resolve final 774 * entry, including configuration and package names. 775 * 776 * @hide 777 */ getLastResourceResolution()778 public @Nullable String getLastResourceResolution() { 779 synchronized (this) { 780 ensureValidLocked(); 781 return nativeGetLastResourceResolution(mObject); 782 } 783 } 784 getPooledStringForCookie(int cookie, int id)785 CharSequence getPooledStringForCookie(int cookie, int id) { 786 // Cookies map to ApkAssets starting at 1. 787 return getApkAssets()[cookie - 1].getStringFromPool(id); 788 } 789 790 /** 791 * Open an asset using ACCESS_STREAMING mode. This provides access to 792 * files that have been bundled with an application as assets -- that is, 793 * files placed in to the "assets" directory. 794 * 795 * @param fileName The name of the asset to open. This name can be hierarchical. 796 * 797 * @see #open(String, int) 798 * @see #list 799 */ open(@onNull String fileName)800 public @NonNull InputStream open(@NonNull String fileName) throws IOException { 801 return open(fileName, ACCESS_STREAMING); 802 } 803 804 /** 805 * Open an asset using an explicit access mode, returning an InputStream to 806 * read its contents. This provides access to files that have been bundled 807 * with an application as assets -- that is, files placed in to the 808 * "assets" directory. 809 * 810 * @param fileName The name of the asset to open. This name can be hierarchical. 811 * @param accessMode Desired access mode for retrieving the data. 812 * 813 * @see #ACCESS_UNKNOWN 814 * @see #ACCESS_STREAMING 815 * @see #ACCESS_RANDOM 816 * @see #ACCESS_BUFFER 817 * @see #open(String) 818 * @see #list 819 */ open(@onNull String fileName, int accessMode)820 public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException { 821 Preconditions.checkNotNull(fileName, "fileName"); 822 synchronized (this) { 823 ensureOpenLocked(); 824 final long asset = nativeOpenAsset(mObject, fileName, accessMode); 825 if (asset == 0) { 826 throw new FileNotFoundException("Asset file: " + fileName); 827 } 828 final AssetInputStream assetInputStream = new AssetInputStream(asset); 829 incRefsLocked(assetInputStream.hashCode()); 830 return assetInputStream; 831 } 832 } 833 834 /** 835 * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}. 836 * This provides access to files that have been bundled with an application as assets -- that 837 * is, files placed in to the "assets" directory. 838 * 839 * The asset must be uncompressed, or an exception will be thrown. 840 * 841 * @param fileName The name of the asset to open. This name can be hierarchical. 842 * @return An open AssetFileDescriptor. 843 */ openFd(@onNull String fileName)844 public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException { 845 Preconditions.checkNotNull(fileName, "fileName"); 846 synchronized (this) { 847 ensureOpenLocked(); 848 final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets); 849 if (pfd == null) { 850 throw new FileNotFoundException("Asset file: " + fileName); 851 } 852 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 853 } 854 } 855 856 /** 857 * Return a String array of all the assets at the given path. 858 * 859 * @param path A relative path within the assets, i.e., "docs/home.html". 860 * 861 * @return String[] Array of strings, one for each asset. These file 862 * names are relative to 'path'. You can open the file by 863 * concatenating 'path' and a name in the returned string (via 864 * File) and passing that to open(). 865 * 866 * @see #open 867 */ list(@onNull String path)868 public @Nullable String[] list(@NonNull String path) throws IOException { 869 Preconditions.checkNotNull(path, "path"); 870 synchronized (this) { 871 ensureValidLocked(); 872 return nativeList(mObject, path); 873 } 874 } 875 876 /** 877 * Open a non-asset file as an asset using ACCESS_STREAMING mode. This 878 * provides direct access to all of the files included in an application 879 * package (not only its assets). Applications should not normally use 880 * this. 881 * 882 * @param fileName Name of the asset to retrieve. 883 * 884 * @see #open(String) 885 * @hide 886 */ 887 @UnsupportedAppUsage openNonAsset(@onNull String fileName)888 public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException { 889 return openNonAsset(0, fileName, ACCESS_STREAMING); 890 } 891 892 /** 893 * Open a non-asset file as an asset using a specific access mode. This 894 * provides direct access to all of the files included in an application 895 * package (not only its assets). Applications should not normally use 896 * this. 897 * 898 * @param fileName Name of the asset to retrieve. 899 * @param accessMode Desired access mode for retrieving the data. 900 * 901 * @see #ACCESS_UNKNOWN 902 * @see #ACCESS_STREAMING 903 * @see #ACCESS_RANDOM 904 * @see #ACCESS_BUFFER 905 * @see #open(String, int) 906 * @hide 907 */ 908 @UnsupportedAppUsage openNonAsset(@onNull String fileName, int accessMode)909 public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode) 910 throws IOException { 911 return openNonAsset(0, fileName, accessMode); 912 } 913 914 /** 915 * Open a non-asset in a specified package. Not for use by applications. 916 * 917 * @param cookie Identifier of the package to be opened. 918 * @param fileName Name of the asset to retrieve. 919 * @hide 920 */ 921 @UnsupportedAppUsage openNonAsset(int cookie, @NonNull String fileName)922 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName) 923 throws IOException { 924 return openNonAsset(cookie, fileName, ACCESS_STREAMING); 925 } 926 927 /** 928 * Open a non-asset in a specified package. Not for use by applications. 929 * 930 * @param cookie Identifier of the package to be opened. 931 * @param fileName Name of the asset to retrieve. 932 * @param accessMode Desired access mode for retrieving the data. 933 * @hide 934 */ 935 @UnsupportedAppUsage openNonAsset(int cookie, @NonNull String fileName, int accessMode)936 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode) 937 throws IOException { 938 Preconditions.checkNotNull(fileName, "fileName"); 939 synchronized (this) { 940 ensureOpenLocked(); 941 final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode); 942 if (asset == 0) { 943 throw new FileNotFoundException("Asset absolute file: " + fileName); 944 } 945 final AssetInputStream assetInputStream = new AssetInputStream(asset); 946 incRefsLocked(assetInputStream.hashCode()); 947 return assetInputStream; 948 } 949 } 950 951 /** 952 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 953 * This provides direct access to all of the files included in an application 954 * package (not only its assets). Applications should not normally use this. 955 * 956 * The asset must not be compressed, or an exception will be thrown. 957 * 958 * @param fileName Name of the asset to retrieve. 959 */ openNonAssetFd(@onNull String fileName)960 public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName) 961 throws IOException { 962 return openNonAssetFd(0, fileName); 963 } 964 965 /** 966 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 967 * This provides direct access to all of the files included in an application 968 * package (not only its assets). Applications should not normally use this. 969 * 970 * The asset must not be compressed, or an exception will be thrown. 971 * 972 * @param cookie Identifier of the package to be opened. 973 * @param fileName Name of the asset to retrieve. 974 */ openNonAssetFd(int cookie, @NonNull String fileName)975 public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName) 976 throws IOException { 977 Preconditions.checkNotNull(fileName, "fileName"); 978 synchronized (this) { 979 ensureOpenLocked(); 980 final ParcelFileDescriptor pfd = 981 nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets); 982 if (pfd == null) { 983 throw new FileNotFoundException("Asset absolute file: " + fileName); 984 } 985 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 986 } 987 } 988 989 /** 990 * Retrieve a parser for a compiled XML file. 991 * 992 * @param fileName The name of the file to retrieve. 993 */ openXmlResourceParser(@onNull String fileName)994 public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName) 995 throws IOException { 996 return openXmlResourceParser(0, fileName); 997 } 998 999 /** 1000 * Retrieve a parser for a compiled XML file. 1001 * 1002 * @param cookie Identifier of the package to be opened. 1003 * @param fileName The name of the file to retrieve. 1004 */ openXmlResourceParser(int cookie, @NonNull String fileName)1005 public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName) 1006 throws IOException { 1007 try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) { 1008 XmlResourceParser parser = block.newParser(); 1009 // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with 1010 // a valid native pointer, which makes newParser always return non-null. But let's 1011 // be paranoid. 1012 if (parser == null) { 1013 throw new AssertionError("block.newParser() returned a null parser"); 1014 } 1015 return parser; 1016 } 1017 } 1018 1019 /** 1020 * Retrieve a non-asset as a compiled XML file. Not for use by applications. 1021 * 1022 * @param fileName The name of the file to retrieve. 1023 * @hide 1024 */ openXmlBlockAsset(@onNull String fileName)1025 @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException { 1026 return openXmlBlockAsset(0, fileName); 1027 } 1028 1029 /** 1030 * Retrieve a non-asset as a compiled XML file. Not for use by 1031 * applications. 1032 * 1033 * @param cookie Identifier of the package to be opened. 1034 * @param fileName Name of the asset to retrieve. 1035 * @hide 1036 */ openXmlBlockAsset(int cookie, @NonNull String fileName)1037 @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException { 1038 Preconditions.checkNotNull(fileName, "fileName"); 1039 synchronized (this) { 1040 ensureOpenLocked(); 1041 final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName); 1042 if (xmlBlock == 0) { 1043 throw new FileNotFoundException("Asset XML file: " + fileName); 1044 } 1045 final XmlBlock block = new XmlBlock(this, xmlBlock); 1046 incRefsLocked(block.hashCode()); 1047 return block; 1048 } 1049 } 1050 xmlBlockGone(int id)1051 void xmlBlockGone(int id) { 1052 synchronized (this) { 1053 decRefsLocked(id); 1054 } 1055 } 1056 1057 @UnsupportedAppUsage applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1058 void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1059 @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, 1060 long outIndicesAddress) { 1061 Preconditions.checkNotNull(inAttrs, "inAttrs"); 1062 synchronized (this) { 1063 // Need to synchronize on AssetManager because we will be accessing 1064 // the native implementation of AssetManager. 1065 ensureValidLocked(); 1066 nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes, 1067 parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress, 1068 outIndicesAddress); 1069 } 1070 } 1071 getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @StyleRes int xmlStyle)1072 int[] getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, 1073 @StyleRes int defStyleRes, @StyleRes int xmlStyle) { 1074 synchronized (this) { 1075 return nativeAttributeResolutionStack( 1076 mObject, themePtr, xmlStyle, defStyleAttr, defStyleRes); 1077 } 1078 } 1079 1080 @UnsupportedAppUsage resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1081 boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1082 @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, 1083 @NonNull int[] outIndices) { 1084 Preconditions.checkNotNull(inAttrs, "inAttrs"); 1085 Preconditions.checkNotNull(outValues, "outValues"); 1086 Preconditions.checkNotNull(outIndices, "outIndices"); 1087 synchronized (this) { 1088 // Need to synchronize on AssetManager because we will be accessing 1089 // the native implementation of AssetManager. 1090 ensureValidLocked(); 1091 return nativeResolveAttrs(mObject, 1092 themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices); 1093 } 1094 } 1095 1096 @UnsupportedAppUsage retrieveAttributes(@onNull XmlBlock.Parser parser, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1097 boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs, 1098 @NonNull int[] outValues, @NonNull int[] outIndices) { 1099 Preconditions.checkNotNull(parser, "parser"); 1100 Preconditions.checkNotNull(inAttrs, "inAttrs"); 1101 Preconditions.checkNotNull(outValues, "outValues"); 1102 Preconditions.checkNotNull(outIndices, "outIndices"); 1103 synchronized (this) { 1104 // Need to synchronize on AssetManager because we will be accessing 1105 // the native implementation of AssetManager. 1106 ensureValidLocked(); 1107 return nativeRetrieveAttributes( 1108 mObject, parser.mParseState, inAttrs, outValues, outIndices); 1109 } 1110 } 1111 1112 @UnsupportedAppUsage createTheme()1113 long createTheme() { 1114 synchronized (this) { 1115 ensureValidLocked(); 1116 long themePtr = nativeThemeCreate(mObject); 1117 incRefsLocked(themePtr); 1118 return themePtr; 1119 } 1120 } 1121 releaseTheme(long themePtr)1122 void releaseTheme(long themePtr) { 1123 synchronized (this) { 1124 nativeThemeDestroy(themePtr); 1125 decRefsLocked(themePtr); 1126 } 1127 } 1128 applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force)1129 void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) { 1130 synchronized (this) { 1131 // Need to synchronize on AssetManager because we will be accessing 1132 // the native implementation of AssetManager. 1133 ensureValidLocked(); 1134 nativeThemeApplyStyle(mObject, themePtr, resId, force); 1135 } 1136 } 1137 1138 @UnsupportedAppUsage setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr)1139 void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) { 1140 synchronized (this) { 1141 ensureValidLocked(); 1142 synchronized (srcAssetManager) { 1143 srcAssetManager.ensureValidLocked(); 1144 nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr); 1145 } 1146 } 1147 } 1148 1149 @Override finalize()1150 protected void finalize() throws Throwable { 1151 if (DEBUG_REFS && mNumRefs != 0) { 1152 Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs); 1153 if (mRefStacks != null) { 1154 for (RuntimeException e : mRefStacks.values()) { 1155 Log.w(TAG, "Reference from here", e); 1156 } 1157 } 1158 } 1159 1160 synchronized (this) { 1161 if (mObject != 0) { 1162 nativeDestroy(mObject); 1163 mObject = 0; 1164 } 1165 } 1166 } 1167 1168 /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread 1169 safe and it does not rely on AssetManager once it has been created. It completely owns the 1170 underlying Asset. */ 1171 public final class AssetInputStream extends InputStream { 1172 private long mAssetNativePtr; 1173 private long mLength; 1174 private long mMarkPos; 1175 1176 /** 1177 * @hide 1178 */ 1179 @UnsupportedAppUsage getAssetInt()1180 public final int getAssetInt() { 1181 throw new UnsupportedOperationException(); 1182 } 1183 1184 /** 1185 * @hide 1186 */ 1187 @UnsupportedAppUsage getNativeAsset()1188 public final long getNativeAsset() { 1189 return mAssetNativePtr; 1190 } 1191 AssetInputStream(long assetNativePtr)1192 private AssetInputStream(long assetNativePtr) { 1193 mAssetNativePtr = assetNativePtr; 1194 mLength = nativeAssetGetLength(assetNativePtr); 1195 } 1196 1197 @Override read()1198 public final int read() throws IOException { 1199 ensureOpen(); 1200 return nativeAssetReadChar(mAssetNativePtr); 1201 } 1202 1203 @Override read(@onNull byte[] b)1204 public final int read(@NonNull byte[] b) throws IOException { 1205 ensureOpen(); 1206 Preconditions.checkNotNull(b, "b"); 1207 return nativeAssetRead(mAssetNativePtr, b, 0, b.length); 1208 } 1209 1210 @Override read(@onNull byte[] b, int off, int len)1211 public final int read(@NonNull byte[] b, int off, int len) throws IOException { 1212 ensureOpen(); 1213 Preconditions.checkNotNull(b, "b"); 1214 return nativeAssetRead(mAssetNativePtr, b, off, len); 1215 } 1216 1217 @Override skip(long n)1218 public final long skip(long n) throws IOException { 1219 ensureOpen(); 1220 long pos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1221 if ((pos + n) > mLength) { 1222 n = mLength - pos; 1223 } 1224 if (n > 0) { 1225 nativeAssetSeek(mAssetNativePtr, n, 0); 1226 } 1227 return n; 1228 } 1229 1230 @Override available()1231 public final int available() throws IOException { 1232 ensureOpen(); 1233 final long len = nativeAssetGetRemainingLength(mAssetNativePtr); 1234 return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len; 1235 } 1236 1237 @Override markSupported()1238 public final boolean markSupported() { 1239 return true; 1240 } 1241 1242 @Override mark(int readlimit)1243 public final void mark(int readlimit) { 1244 ensureOpen(); 1245 mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1246 } 1247 1248 @Override reset()1249 public final void reset() throws IOException { 1250 ensureOpen(); 1251 nativeAssetSeek(mAssetNativePtr, mMarkPos, -1); 1252 } 1253 1254 @Override close()1255 public final void close() throws IOException { 1256 if (mAssetNativePtr != 0) { 1257 nativeAssetDestroy(mAssetNativePtr); 1258 mAssetNativePtr = 0; 1259 1260 synchronized (AssetManager.this) { 1261 decRefsLocked(hashCode()); 1262 } 1263 } 1264 } 1265 1266 @Override finalize()1267 protected void finalize() throws Throwable { 1268 close(); 1269 } 1270 ensureOpen()1271 private void ensureOpen() { 1272 if (mAssetNativePtr == 0) { 1273 throw new IllegalStateException("AssetInputStream is closed"); 1274 } 1275 } 1276 } 1277 1278 /** 1279 * Determine whether the state in this asset manager is up-to-date with 1280 * the files on the filesystem. If false is returned, you need to 1281 * instantiate a new AssetManager class to see the new data. 1282 * @hide 1283 */ 1284 @UnsupportedAppUsage isUpToDate()1285 public boolean isUpToDate() { 1286 synchronized (this) { 1287 if (!mOpen) { 1288 return false; 1289 } 1290 1291 for (ApkAssets apkAssets : mApkAssets) { 1292 if (!apkAssets.isUpToDate()) { 1293 return false; 1294 } 1295 } 1296 1297 return true; 1298 } 1299 } 1300 1301 /** 1302 * Get the locales that this asset manager contains data for. 1303 * 1304 * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid 1305 * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be 1306 * parsed using {@link java.util.Locale#forLanguageTag(String)}. 1307 * 1308 * <p>On SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings 1309 * are of the form {@code ll_CC} where {@code ll} is a two letter language code, 1310 * and {@code CC} is a two letter country code. 1311 */ getLocales()1312 public String[] getLocales() { 1313 synchronized (this) { 1314 ensureValidLocked(); 1315 return nativeGetLocales(mObject, false /*excludeSystem*/); 1316 } 1317 } 1318 1319 /** 1320 * Same as getLocales(), except that locales that are only provided by the system (i.e. those 1321 * present in framework-res.apk or its overlays) will not be listed. 1322 * 1323 * For example, if the "system" assets support English, French, and German, and the additional 1324 * assets support Cherokee and French, getLocales() would return 1325 * [Cherokee, English, French, German], while getNonSystemLocales() would return 1326 * [Cherokee, French]. 1327 * @hide 1328 */ getNonSystemLocales()1329 public String[] getNonSystemLocales() { 1330 synchronized (this) { 1331 ensureValidLocked(); 1332 return nativeGetLocales(mObject, true /*excludeSystem*/); 1333 } 1334 } 1335 1336 /** 1337 * @hide 1338 */ getSizeConfigurations()1339 Configuration[] getSizeConfigurations() { 1340 synchronized (this) { 1341 ensureValidLocked(); 1342 return nativeGetSizeConfigurations(mObject); 1343 } 1344 } 1345 1346 /** 1347 * Change the configuration used when retrieving resources. Not for use by 1348 * applications. 1349 * @hide 1350 */ 1351 @UnsupportedAppUsage setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion)1352 public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation, 1353 int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, 1354 int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, 1355 int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) { 1356 synchronized (this) { 1357 ensureValidLocked(); 1358 nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density, 1359 keyboard, keyboardHidden, navigation, screenWidth, screenHeight, 1360 smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, 1361 colorMode, majorVersion); 1362 } 1363 } 1364 1365 /** 1366 * @hide 1367 */ 1368 @UnsupportedAppUsage getAssignedPackageIdentifiers()1369 public SparseArray<String> getAssignedPackageIdentifiers() { 1370 synchronized (this) { 1371 ensureValidLocked(); 1372 return nativeGetAssignedPackageIdentifiers(mObject); 1373 } 1374 } 1375 1376 /** 1377 * @hide 1378 */ 1379 @TestApi 1380 @GuardedBy("this") getOverlayableMap(String packageName)1381 public @Nullable Map<String, String> getOverlayableMap(String packageName) { 1382 synchronized (this) { 1383 ensureValidLocked(); 1384 return nativeGetOverlayableMap(mObject, packageName); 1385 } 1386 } 1387 1388 @GuardedBy("this") incRefsLocked(long id)1389 private void incRefsLocked(long id) { 1390 if (DEBUG_REFS) { 1391 if (mRefStacks == null) { 1392 mRefStacks = new HashMap<>(); 1393 } 1394 RuntimeException ex = new RuntimeException(); 1395 ex.fillInStackTrace(); 1396 mRefStacks.put(id, ex); 1397 } 1398 mNumRefs++; 1399 } 1400 1401 @GuardedBy("this") decRefsLocked(long id)1402 private void decRefsLocked(long id) { 1403 if (DEBUG_REFS && mRefStacks != null) { 1404 mRefStacks.remove(id); 1405 } 1406 mNumRefs--; 1407 if (mNumRefs == 0 && mObject != 0) { 1408 nativeDestroy(mObject); 1409 mObject = 0; 1410 mApkAssets = sEmptyApkAssets; 1411 } 1412 } 1413 1414 // AssetManager setup native methods. nativeCreate()1415 private static native long nativeCreate(); nativeDestroy(long ptr)1416 private static native void nativeDestroy(long ptr); nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, boolean invalidateCaches)1417 private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, 1418 boolean invalidateCaches); nativeSetConfiguration(long ptr, int mcc, int mnc, @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion)1419 private static native void nativeSetConfiguration(long ptr, int mcc, int mnc, 1420 @Nullable String locale, int orientation, int touchscreen, int density, int keyboard, 1421 int keyboardHidden, int navigation, int screenWidth, int screenHeight, 1422 int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, 1423 int uiMode, int colorMode, int majorVersion); nativeGetAssignedPackageIdentifiers( long ptr)1424 private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers( 1425 long ptr); 1426 1427 // File native methods. nativeList(long ptr, @NonNull String path)1428 private static native @Nullable String[] nativeList(long ptr, @NonNull String path) 1429 throws IOException; nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode)1430 private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode); nativeOpenAssetFd(long ptr, @NonNull String fileName, long[] outOffsets)1431 private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr, 1432 @NonNull String fileName, long[] outOffsets) throws IOException; nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, int accessMode)1433 private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, 1434 int accessMode); nativeOpenNonAssetFd(long ptr, int cookie, @NonNull String fileName, @NonNull long[] outOffsets)1435 private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie, 1436 @NonNull String fileName, @NonNull long[] outOffsets) throws IOException; nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName)1437 private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName); 1438 1439 // Primitive resource native methods. nativeGetResourceValue(long ptr, @AnyRes int resId, short density, @NonNull TypedValue outValue, boolean resolveReferences)1440 private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density, 1441 @NonNull TypedValue outValue, boolean resolveReferences); nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, @NonNull TypedValue outValue)1442 private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, 1443 @NonNull TypedValue outValue); 1444 nativeGetStyleAttributes(long ptr, @StyleRes int resId)1445 private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr, 1446 @StyleRes int resId); nativeGetResourceStringArray(long ptr, @ArrayRes int resId)1447 private static native @Nullable String[] nativeGetResourceStringArray(long ptr, 1448 @ArrayRes int resId); nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resId)1449 private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr, 1450 @ArrayRes int resId); nativeGetResourceIntArray(long ptr, @ArrayRes int resId)1451 private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId); nativeGetResourceArraySize(long ptr, @ArrayRes int resId)1452 private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId); nativeGetResourceArray(long ptr, @ArrayRes int resId, @NonNull int[] outValues)1453 private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId, 1454 @NonNull int[] outValues); 1455 1456 // Resource name/ID native methods. nativeGetResourceIdentifier(long ptr, @NonNull String name, @Nullable String defType, @Nullable String defPackage)1457 private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name, 1458 @Nullable String defType, @Nullable String defPackage); nativeGetResourceName(long ptr, @AnyRes int resid)1459 private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid); nativeGetResourcePackageName(long ptr, @AnyRes int resid)1460 private static native @Nullable String nativeGetResourcePackageName(long ptr, 1461 @AnyRes int resid); nativeGetResourceTypeName(long ptr, @AnyRes int resid)1462 private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid); nativeGetResourceEntryName(long ptr, @AnyRes int resid)1463 private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); nativeGetLocales(long ptr, boolean excludeSystem)1464 private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); nativeGetSizeConfigurations(long ptr)1465 private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled)1466 private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); nativeGetLastResourceResolution(long ptr)1467 private static native @Nullable String nativeGetLastResourceResolution(long ptr); 1468 1469 // Style attribute retrieval native methods. nativeAttributeResolutionStack(long ptr, long themePtr, @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)1470 private static native int[] nativeAttributeResolutionStack(long ptr, long themePtr, 1471 @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes); nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1472 private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, 1473 @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, 1474 long outValuesAddress, long outIndicesAddress); nativeResolveAttrs(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1475 private static native boolean nativeResolveAttrs(long ptr, long themePtr, 1476 @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, 1477 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); nativeRetrieveAttributes(long ptr, long xmlParserPtr, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1478 private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr, 1479 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); 1480 1481 // Theme related native methods nativeThemeCreate(long ptr)1482 private static native long nativeThemeCreate(long ptr); nativeThemeDestroy(long themePtr)1483 private static native void nativeThemeDestroy(long themePtr); nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, boolean force)1484 private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, 1485 boolean force); nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, long srcAssetManagerPtr, long srcThemePtr)1486 private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, 1487 long srcAssetManagerPtr, long srcThemePtr); nativeThemeClear(long themePtr)1488 static native void nativeThemeClear(long themePtr); nativeThemeGetAttributeValue(long ptr, long themePtr, @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve)1489 private static native int nativeThemeGetAttributeValue(long ptr, long themePtr, 1490 @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve); nativeThemeDump(long ptr, long themePtr, int priority, String tag, String prefix)1491 private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag, 1492 String prefix); nativeThemeGetChangingConfigurations(long themePtr)1493 static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr); 1494 1495 // AssetInputStream related native methods. nativeAssetDestroy(long assetPtr)1496 private static native void nativeAssetDestroy(long assetPtr); nativeAssetReadChar(long assetPtr)1497 private static native int nativeAssetReadChar(long assetPtr); nativeAssetRead(long assetPtr, byte[] b, int off, int len)1498 private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len); nativeAssetSeek(long assetPtr, long offset, int whence)1499 private static native long nativeAssetSeek(long assetPtr, long offset, int whence); nativeAssetGetLength(long assetPtr)1500 private static native long nativeAssetGetLength(long assetPtr); nativeAssetGetRemainingLength(long assetPtr)1501 private static native long nativeAssetGetRemainingLength(long assetPtr); 1502 nativeVerifySystemIdmaps()1503 private static native void nativeVerifySystemIdmaps(); nativeCreateIdmapsForStaticOverlaysTargetingAndroid()1504 private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid(); nativeGetOverlayableMap(long ptr, @NonNull String packageName)1505 private static native @Nullable Map nativeGetOverlayableMap(long ptr, 1506 @NonNull String packageName); 1507 1508 // Global debug native methods. 1509 /** 1510 * @hide 1511 */ 1512 @UnsupportedAppUsage getGlobalAssetCount()1513 public static native int getGlobalAssetCount(); 1514 1515 /** 1516 * @hide 1517 */ getAssetAllocations()1518 public static native String getAssetAllocations(); 1519 1520 /** 1521 * @hide 1522 */ 1523 @UnsupportedAppUsage getGlobalAssetManagerCount()1524 public static native int getGlobalAssetManagerCount(); 1525 } 1526