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 static android.app.ResourcesManager.ApkKey; 20 import static android.content.res.Resources.ID_NULL; 21 22 import android.annotation.AnyRes; 23 import android.annotation.ArrayRes; 24 import android.annotation.AttrRes; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.StringRes; 28 import android.annotation.StyleRes; 29 import android.annotation.TestApi; 30 import android.app.ResourcesManager; 31 import android.compat.annotation.UnsupportedAppUsage; 32 import android.content.pm.ActivityInfo; 33 import android.content.res.Configuration.NativeConfig; 34 import android.content.res.loader.ResourcesLoader; 35 import android.os.Build; 36 import android.os.ParcelFileDescriptor; 37 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 38 import android.ravenwood.annotation.RavenwoodReplace; 39 import android.ravenwood.annotation.RavenwoodThrow; 40 import android.util.ArrayMap; 41 import android.util.ArraySet; 42 import android.util.Log; 43 import android.util.SparseArray; 44 import android.util.TypedValue; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.content.om.OverlayConfig; 49 import com.android.internal.ravenwood.RavenwoodEnvironment; 50 51 import java.io.FileDescriptor; 52 import java.io.FileNotFoundException; 53 import java.io.IOException; 54 import java.io.InputStream; 55 import java.io.PrintWriter; 56 import java.lang.ref.Reference; 57 import java.util.ArrayList; 58 import java.util.Arrays; 59 import java.util.Collections; 60 import java.util.HashMap; 61 import java.util.List; 62 import java.util.Locale; 63 import java.util.Map; 64 import java.util.Objects; 65 import java.util.concurrent.atomic.AtomicInteger; 66 67 /** 68 * Provides access to an application's raw asset files; see {@link Resources} 69 * for the way most applications will want to retrieve their resource data. 70 * This class presents a lower-level API that allows you to open and read raw 71 * files that have been bundled with the application as a simple stream of 72 * bytes. 73 */ 74 @RavenwoodKeepWholeClass 75 public final class AssetManager implements AutoCloseable { 76 private static final String TAG = "AssetManager"; 77 private static final boolean DEBUG_REFS = false; 78 79 /** 80 * @hide 81 */ 82 public static final String FRAMEWORK_APK_PATH = getFrameworkApkPath(); 83 private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk"; 84 private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk"; 85 86 private static final Object sSync = new Object(); 87 88 private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0]; 89 90 // Not private for LayoutLib's BridgeAssetManager. 91 @UnsupportedAppUsage 92 @GuardedBy("sSync") static AssetManager sSystem = null; 93 94 @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0]; 95 @GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet; 96 97 /** 98 * Cookie value to use when the actual cookie is unknown. This value tells the system to search 99 * all the ApkAssets for the asset. 100 * @hide 101 */ 102 public static final int COOKIE_UNKNOWN = -1; 103 104 /** 105 * Mode for {@link #open(String, int)}: no specific information about how 106 * data will be accessed. 107 */ 108 public static final int ACCESS_UNKNOWN = 0; 109 /** 110 * Mode for {@link #open(String, int)}: Read chunks, and seek forward and 111 * backward. 112 */ 113 public static final int ACCESS_RANDOM = 1; 114 /** 115 * Mode for {@link #open(String, int)}: Read sequentially, with an 116 * occasional forward seek. 117 */ 118 public static final int ACCESS_STREAMING = 2; 119 /** 120 * Mode for {@link #open(String, int)}: Attempt to load contents into 121 * memory, for fast small reads. 122 */ 123 public static final int ACCESS_BUFFER = 3; 124 125 @GuardedBy("this") private final TypedValue mValue = new TypedValue(); 126 @GuardedBy("this") private final long[] mOffsets = new long[2]; 127 128 // Pointer to native implementation, stuffed inside a long. 129 @UnsupportedAppUsage 130 @GuardedBy("this") private long mObject; 131 132 // The loaded asset paths. 133 @GuardedBy("this") private ApkAssets[] mApkAssets; 134 135 // Debug/reference counting implementation. 136 @GuardedBy("this") private boolean mOpen = true; 137 private AtomicInteger mNumRefs = new AtomicInteger(1); 138 @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks; 139 140 private ResourcesLoader[] mLoaders; 141 142 /** 143 * A Builder class that helps create an AssetManager with only a single invocation of 144 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. Without using this builder, 145 * AssetManager must ensure there are system ApkAssets loaded at all times, which when combined 146 * with the user's call to add additional ApkAssets, results in multiple calls to 147 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. 148 * @hide 149 */ 150 public static class Builder { 151 private final ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>(); 152 private final ArrayList<ResourcesLoader> mLoaders = new ArrayList<>(); 153 154 private boolean mNoInit = false; 155 addApkAssets(ApkAssets apkAssets)156 public Builder addApkAssets(ApkAssets apkAssets) { 157 mUserApkAssets.add(apkAssets); 158 return this; 159 } 160 161 @RavenwoodThrow(blockedBy = ResourcesLoader.class) addLoader(ResourcesLoader loader)162 public Builder addLoader(ResourcesLoader loader) { 163 mLoaders.add(loader); 164 return this; 165 } 166 setNoInit()167 public Builder setNoInit() { 168 mNoInit = true; 169 return this; 170 } 171 build()172 public AssetManager build() { 173 // Retrieving the system ApkAssets forces their creation as well. 174 final ApkAssets[] systemApkAssets = getSystem().getApkAssets(); 175 176 // Filter ApkAssets so that assets provided by multiple loaders are only included once 177 // in the AssetManager assets. The last appearance of the ApkAssets dictates its load 178 // order. 179 final ArrayList<ApkAssets> loaderApkAssets = new ArrayList<>(); 180 final ArraySet<ApkAssets> uniqueLoaderApkAssets = new ArraySet<>(); 181 for (int i = mLoaders.size() - 1; i >= 0; i--) { 182 final List<ApkAssets> currentLoaderApkAssets = mLoaders.get(i).getApkAssets(); 183 for (int j = currentLoaderApkAssets.size() - 1; j >= 0; j--) { 184 final ApkAssets apkAssets = currentLoaderApkAssets.get(j); 185 if (uniqueLoaderApkAssets.add(apkAssets)) { 186 loaderApkAssets.add(0, apkAssets); 187 } 188 } 189 } 190 191 final int totalApkAssetCount = systemApkAssets.length + mUserApkAssets.size() 192 + loaderApkAssets.size(); 193 final ApkAssets[] apkAssets = new ApkAssets[totalApkAssetCount]; 194 195 System.arraycopy(systemApkAssets, 0, apkAssets, 0, systemApkAssets.length); 196 197 // Append user ApkAssets after system ApkAssets. 198 for (int i = 0, n = mUserApkAssets.size(); i < n; i++) { 199 apkAssets[i + systemApkAssets.length] = mUserApkAssets.get(i); 200 } 201 202 // Append ApkAssets provided by loaders to the end. 203 for (int i = 0, n = loaderApkAssets.size(); i < n; i++) { 204 apkAssets[i + systemApkAssets.length + mUserApkAssets.size()] = 205 loaderApkAssets.get(i); 206 } 207 208 // Calling this constructor prevents creation of system ApkAssets, which we took care 209 // of in this Builder. 210 final AssetManager assetManager = new AssetManager(false /*sentinel*/); 211 assetManager.mApkAssets = apkAssets; 212 AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets, 213 false /*invalidateCaches*/, mNoInit /*preset*/); 214 assetManager.mLoaders = mLoaders.isEmpty() ? null 215 : mLoaders.toArray(new ResourcesLoader[0]); 216 217 return assetManager; 218 } 219 } 220 221 @RavenwoodReplace getFrameworkApkPath()222 private static String getFrameworkApkPath() { 223 return FRAMEWORK_APK_PATH_DEVICE; 224 } 225 getFrameworkApkPath$ravenwood()226 private static String getFrameworkApkPath$ravenwood() { 227 return RavenwoodEnvironment.getInstance().getRavenwoodRuntimePath() 228 + FRAMEWORK_APK_PATH_RAVENWOOD; 229 } 230 231 /** 232 * Create a new AssetManager containing only the basic system assets. 233 * Applications will not generally use this method, instead retrieving the 234 * appropriate asset manager with {@link Resources#getAssets}. Not for 235 * use by applications. 236 * @hide 237 */ 238 @UnsupportedAppUsage AssetManager()239 public AssetManager() { 240 final ApkAssets[] assets; 241 synchronized (sSync) { 242 createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); 243 assets = sSystemApkAssets; 244 } 245 246 mObject = nativeCreate(); 247 if (DEBUG_REFS) { 248 mNumRefs.set(0); 249 incRefsLocked(hashCode()); 250 } 251 252 // Always set the framework resources. 253 setApkAssets(assets, false /*invalidateCaches*/); 254 } 255 256 /** 257 * Private constructor that doesn't call ensureSystemAssets. 258 * Used for the creation of system assets. 259 */ 260 @SuppressWarnings("unused") AssetManager(boolean sentinel)261 private AssetManager(boolean sentinel) { 262 mObject = nativeCreate(); 263 if (DEBUG_REFS) { 264 mNumRefs.set(0); 265 incRefsLocked(hashCode()); 266 } 267 } 268 269 /** 270 * This must be called from Zygote so that system assets are shared by all applications. 271 * @hide 272 */ 273 @GuardedBy("sSync") 274 @VisibleForTesting createSystemAssetsInZygoteLocked(boolean reinitialize, String frameworkPath)275 public static void createSystemAssetsInZygoteLocked(boolean reinitialize, 276 String frameworkPath) { 277 if (sSystem != null && !reinitialize) { 278 return; 279 } 280 281 try { 282 final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); 283 apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM)); 284 285 // TODO(Ravenwood): overlay support? 286 final String[] systemIdmapPaths = 287 RavenwoodEnvironment.getInstance().isRunningOnRavenwood() ? new String[0] : 288 OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); 289 for (String idmapPath : systemIdmapPaths) { 290 apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); 291 } 292 293 sSystemApkAssetsSet = new ArraySet<>(apkAssets); 294 sSystemApkAssets = apkAssets.toArray(new ApkAssets[0]); 295 if (sSystem == null) { 296 sSystem = new AssetManager(true /*sentinel*/); 297 } 298 sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/); 299 } catch (IOException e) { 300 throw new IllegalStateException("Failed to create system AssetManager", e); 301 } 302 } 303 304 /** 305 * Return a global shared asset manager that provides access to only 306 * system assets (no application assets). 307 * @hide 308 */ 309 @UnsupportedAppUsage getSystem()310 public static AssetManager getSystem() { 311 synchronized (sSync) { 312 createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); 313 return sSystem; 314 } 315 } 316 317 /** 318 * Close this asset manager. 319 */ 320 @Override close()321 public void close() { 322 synchronized (this) { 323 if (!mOpen) { 324 return; 325 } 326 327 mOpen = false; 328 decRefs(hashCode()); 329 } 330 } 331 332 /** 333 * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)} 334 * family of methods. 335 * 336 * @param apkAssets The new set of paths. 337 * @param invalidateCaches Whether to invalidate any caches. This should almost always be true. 338 * Set this to false if you are appending new resources 339 * (not new configurations). 340 * @hide 341 */ setApkAssets(@onNull ApkAssets[] apkAssets, boolean invalidateCaches)342 public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) { 343 Objects.requireNonNull(apkAssets, "apkAssets"); 344 345 ApkAssets[] newApkAssets = new ApkAssets[sSystemApkAssets.length + apkAssets.length]; 346 347 // Copy the system assets first. 348 System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length); 349 350 // Copy the given ApkAssets if they are not already in the system list. 351 int newLength = sSystemApkAssets.length; 352 for (ApkAssets apkAsset : apkAssets) { 353 if (!sSystemApkAssetsSet.contains(apkAsset)) { 354 newApkAssets[newLength++] = apkAsset; 355 } 356 } 357 358 // Truncate if necessary. 359 if (newLength != newApkAssets.length) { 360 newApkAssets = Arrays.copyOf(newApkAssets, newLength); 361 } 362 363 synchronized (this) { 364 ensureOpenLocked(); 365 mApkAssets = newApkAssets; 366 nativeSetApkAssets(mObject, mApkAssets, invalidateCaches, false); 367 if (invalidateCaches) { 368 // Invalidate all caches. 369 invalidateCachesLocked(-1); 370 } 371 } 372 } 373 374 /** 375 * Changes the {@link ResourcesLoader ResourcesLoaders} used in this AssetManager. 376 * @hide 377 */ 378 @RavenwoodThrow(blockedBy = ResourcesLoader.class) setLoaders(@onNull List<ResourcesLoader> newLoaders)379 void setLoaders(@NonNull List<ResourcesLoader> newLoaders) { 380 Objects.requireNonNull(newLoaders, "newLoaders"); 381 382 final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); 383 for (int i = 0; i < mApkAssets.length; i++) { 384 // Filter out the previous loader apk assets. 385 if (!mApkAssets[i].isForLoader()) { 386 apkAssets.add(mApkAssets[i]); 387 } 388 } 389 390 if (!newLoaders.isEmpty()) { 391 // Filter so that assets provided by multiple loaders are only included once 392 // in the final assets list. The last appearance of the ApkAssets dictates its load 393 // order. 394 final int loaderStartIndex = apkAssets.size(); 395 final ArraySet<ApkAssets> uniqueLoaderApkAssets = new ArraySet<>(); 396 for (int i = newLoaders.size() - 1; i >= 0; i--) { 397 final List<ApkAssets> currentLoaderApkAssets = newLoaders.get(i).getApkAssets(); 398 for (int j = currentLoaderApkAssets.size() - 1; j >= 0; j--) { 399 final ApkAssets loaderApkAssets = currentLoaderApkAssets.get(j); 400 if (uniqueLoaderApkAssets.add(loaderApkAssets)) { 401 apkAssets.add(loaderStartIndex, loaderApkAssets); 402 } 403 } 404 } 405 } 406 407 mLoaders = newLoaders.toArray(new ResourcesLoader[0]); 408 setApkAssets(apkAssets.toArray(new ApkAssets[0]), true /* invalidate_caches */); 409 } 410 411 /** 412 * Invalidates the caches in this AssetManager according to the bitmask `diff`. 413 * 414 * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}. 415 * @see ActivityInfo.Config 416 */ invalidateCachesLocked(int diff)417 private void invalidateCachesLocked(int diff) { 418 // TODO(adamlesinski): Currently there are no caches to invalidate in Java code. 419 } 420 421 /** 422 * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this 423 * returns a 0-length array. 424 * @hide 425 */ 426 @UnsupportedAppUsage getApkAssets()427 public @NonNull ApkAssets[] getApkAssets() { 428 synchronized (this) { 429 if (mOpen) { 430 return mApkAssets; 431 } 432 } 433 return sEmptyApkAssets; 434 } 435 436 /** @hide */ 437 @TestApi getApkPaths()438 public @NonNull String[] getApkPaths() { 439 synchronized (this) { 440 if (mOpen) { 441 String[] paths = new String[mApkAssets.length]; 442 final int count = mApkAssets.length; 443 for (int i = 0; i < count; i++) { 444 paths[i] = mApkAssets[i].getAssetPath(); 445 } 446 return paths; 447 } 448 } 449 return new String[0]; 450 } 451 452 /** 453 * Returns a cookie for use with the other APIs of AssetManager. 454 * @return 0 if the path was not found, otherwise a positive integer cookie representing 455 * this path in the AssetManager. 456 * @hide 457 */ findCookieForPath(@onNull String path)458 public int findCookieForPath(@NonNull String path) { 459 Objects.requireNonNull(path, "path"); 460 synchronized (this) { 461 ensureValidLocked(); 462 final int count = mApkAssets.length; 463 for (int i = 0; i < count; i++) { 464 if (path.equals(mApkAssets[i].getAssetPath())) { 465 return i + 1; 466 } 467 } 468 } 469 return 0; 470 } 471 472 /** 473 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 474 * @hide 475 */ 476 @Deprecated 477 @UnsupportedAppUsage addAssetPath(String path)478 public int addAssetPath(String path) { 479 return addAssetPathInternal(List.of(new ApkKey(path, false, false)), false); 480 } 481 482 /** 483 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 484 * @hide 485 */ 486 @Deprecated 487 @UnsupportedAppUsage addAssetPathAsSharedLibrary(String path)488 public int addAssetPathAsSharedLibrary(String path) { 489 return addAssetPathInternal(List.of(new ApkKey(path, true, false)), false); 490 } 491 492 /** 493 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 494 * @hide 495 */ 496 @Deprecated 497 @UnsupportedAppUsage addOverlayPath(String path)498 public int addOverlayPath(String path) { 499 return addAssetPathInternal(List.of(new ApkKey(path, false, true)), false); 500 } 501 502 /** 503 * @hide 504 */ addPresetApkKeys(@onNull List<ApkKey> keys)505 public void addPresetApkKeys(@NonNull List<ApkKey> keys) { 506 addAssetPathInternal(keys, true); 507 } 508 addAssetPathInternal(List<ApkKey> apkKeys, boolean presetAssets)509 private int addAssetPathInternal(List<ApkKey> apkKeys, boolean presetAssets) { 510 Objects.requireNonNull(apkKeys, "apkKeys"); 511 if (apkKeys.isEmpty()) { 512 return 0; 513 } 514 515 synchronized (this) { 516 ensureOpenLocked(); 517 518 // See if we already have some of the apkKeys loaded. 519 final int originalAssetsCount = mApkAssets.length; 520 521 // Getting an assets' path is a relatively expensive operation, cache them. 522 final ArrayMap<String, Integer> assetPaths = new ArrayMap<>(originalAssetsCount); 523 for (int i = 0; i < originalAssetsCount; i++) { 524 assetPaths.put(mApkAssets[i].getAssetPath(), i); 525 } 526 527 final var newKeys = new ArrayList<ApkKey>(apkKeys.size()); 528 int lastFoundIndex = -1; 529 for (int i = 0, pathsSize = apkKeys.size(); i < pathsSize; i++) { 530 final var key = apkKeys.get(i); 531 final var index = assetPaths.get(key.path); 532 if (index == null) { 533 newKeys.add(key); 534 } else { 535 lastFoundIndex = index; 536 } 537 } 538 if (newKeys.isEmpty()) { 539 return lastFoundIndex + 1; 540 } 541 542 final var newAssets = loadAssets(newKeys); 543 if (newAssets.isEmpty()) { 544 return 0; 545 } 546 mApkAssets = makeNewAssetsArrayLocked(newAssets); 547 nativeSetApkAssets(mObject, mApkAssets, true, presetAssets); 548 invalidateCachesLocked(-1); 549 return originalAssetsCount + 1; 550 } 551 } 552 553 /** 554 * Insert the new assets preserving the correct order: all non-loader assets go before all 555 * of the loader assets. 556 */ 557 @GuardedBy("this") makeNewAssetsArrayLocked( @onNull ArrayList<ApkAssets> newNonLoaderAssets)558 private @NonNull ApkAssets[] makeNewAssetsArrayLocked( 559 @NonNull ArrayList<ApkAssets> newNonLoaderAssets) { 560 final int originalAssetsCount = mApkAssets.length; 561 int firstLoaderIndex = originalAssetsCount; 562 for (int i = 0; i < originalAssetsCount; i++) { 563 if (mApkAssets[i].isForLoader()) { 564 firstLoaderIndex = i; 565 break; 566 } 567 } 568 final int newAssetsSize = newNonLoaderAssets.size(); 569 final var newAssetsArray = new ApkAssets[originalAssetsCount + newAssetsSize]; 570 if (firstLoaderIndex > 0) { 571 // This should always be true, but who knows... 572 System.arraycopy(mApkAssets, 0, newAssetsArray, 0, firstLoaderIndex); 573 } 574 for (int i = 0; i < newAssetsSize; i++) { 575 newAssetsArray[firstLoaderIndex + i] = newNonLoaderAssets.get(i); 576 } 577 if (originalAssetsCount > firstLoaderIndex) { 578 System.arraycopy( 579 mApkAssets, firstLoaderIndex, 580 newAssetsArray, firstLoaderIndex + newAssetsSize, 581 originalAssetsCount - firstLoaderIndex); 582 } 583 return newAssetsArray; 584 } 585 loadAssets(@onNull ArrayList<ApkKey> keys)586 private static @NonNull ArrayList<ApkAssets> loadAssets(@NonNull ArrayList<ApkKey> keys) { 587 final int pathsSize = keys.size(); 588 final var loadedAssets = new ArrayList<ApkAssets>(pathsSize); 589 final var resourcesManager = ResourcesManager.getInstance(); 590 for (int i = 0; i < pathsSize; i++) { 591 final var key = keys.get(i); 592 try { 593 // ResourcesManager has a cache of loaded assets, ensuring we don't open the same 594 // file repeatedly, which is useful for the common overlays and registered 595 // shared libraries. 596 loadedAssets.add(resourcesManager.loadApkAssets(key)); 597 } catch (IOException e) { 598 Log.w(TAG, "Failed to load asset, key = " + key, e); 599 } 600 } 601 return loadedAssets; 602 } 603 604 /** @hide */ 605 @NonNull 606 @RavenwoodThrow(blockedBy = ResourcesLoader.class) getLoaders()607 public List<ResourcesLoader> getLoaders() { 608 return mLoaders == null ? Collections.emptyList() : Arrays.asList(mLoaders); 609 } 610 611 /** 612 * Ensures that the native implementation has not been destroyed. 613 * The AssetManager may have been closed, but references to it still exist 614 * and therefore the native implementation is not destroyed. 615 */ 616 @GuardedBy("this") ensureValidLocked()617 private void ensureValidLocked() { 618 if (mObject == 0) { 619 throw new RuntimeException("AssetManager has been destroyed"); 620 } 621 } 622 623 /** 624 * Ensures that the AssetManager has not been explicitly closed. If this method passes, 625 * then this implies that ensureValidLocked() also passes. 626 */ 627 @GuardedBy("this") ensureOpenLocked()628 private void ensureOpenLocked() { 629 // If mOpen is true, this implies that mObject != 0. 630 if (!mOpen) { 631 throw new RuntimeException("AssetManager has been closed"); 632 } 633 // Let's still check if the native object exists, given all the memory corruptions. 634 if (mObject == 0) { 635 throw new RuntimeException("AssetManager is open but the native object is gone"); 636 } 637 } 638 639 /** 640 * Populates {@code outValue} with the data associated a particular 641 * resource identifier for the current configuration. 642 * 643 * @param resId the resource identifier to load 644 * @param densityDpi the density bucket for which to load the resource 645 * @param outValue the typed value in which to put the data 646 * @param resolveRefs {@code true} to resolve references, {@code false} 647 * to leave them unresolved 648 * @return {@code true} if the data was loaded into {@code outValue}, 649 * {@code false} otherwise 650 */ 651 @UnsupportedAppUsage getResourceValue(@nyRes int resId, int densityDpi, @NonNull TypedValue outValue, boolean resolveRefs)652 boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue, 653 boolean resolveRefs) { 654 Objects.requireNonNull(outValue, "outValue"); 655 synchronized (this) { 656 ensureValidLocked(); 657 final int cookie = nativeGetResourceValue( 658 mObject, resId, (short) densityDpi, outValue, resolveRefs); 659 if (cookie <= 0) { 660 return false; 661 } 662 663 // Convert the changing configurations flags populated by native code. 664 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 665 outValue.changingConfigurations); 666 667 if (outValue.type == TypedValue.TYPE_STRING) { 668 if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) { 669 return false; 670 } 671 } 672 return true; 673 } 674 } 675 676 /** 677 * Retrieves the string value associated with a particular resource 678 * identifier for the current configuration. 679 * 680 * @param resId the resource identifier to load 681 * @return the string value, or {@code null} 682 */ 683 @UnsupportedAppUsage getResourceText(@tringRes int resId)684 @Nullable CharSequence getResourceText(@StringRes int resId) { 685 synchronized (this) { 686 final TypedValue outValue = mValue; 687 if (getResourceValue(resId, 0, outValue, true)) { 688 return outValue.coerceToString(); 689 } 690 return null; 691 } 692 } 693 694 /** 695 * Retrieves the string value associated with a particular resource 696 * identifier for the current configuration. 697 * 698 * @param resId the resource identifier to load 699 * @param bagEntryId the index into the bag to load 700 * @return the string value, or {@code null} 701 */ 702 @UnsupportedAppUsage getResourceBagText(@tringRes int resId, int bagEntryId)703 @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) { 704 synchronized (this) { 705 ensureValidLocked(); 706 final TypedValue outValue = mValue; 707 final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue); 708 if (cookie <= 0) { 709 return null; 710 } 711 712 // Convert the changing configurations flags populated by native code. 713 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 714 outValue.changingConfigurations); 715 716 if (outValue.type == TypedValue.TYPE_STRING) { 717 return getPooledStringForCookie(cookie, outValue.data); 718 } 719 return outValue.coerceToString(); 720 } 721 } 722 getResourceArraySize(@rrayRes int resId)723 int getResourceArraySize(@ArrayRes int resId) { 724 synchronized (this) { 725 ensureValidLocked(); 726 return nativeGetResourceArraySize(mObject, resId); 727 } 728 } 729 730 /** 731 * Populates `outData` with array elements of `resId`. `outData` is normally 732 * used with 733 * {@link TypedArray}. 734 * 735 * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES} 736 * long, 737 * with the indices of the data representing the type, value, asset cookie, 738 * resource ID, 739 * configuration change mask, and density of the element. 740 * 741 * @param resId The resource ID of an array resource. 742 * @param outData The array to populate with data. 743 * @return The length of the array. 744 * 745 * @see TypedArray#STYLE_TYPE 746 * @see TypedArray#STYLE_DATA 747 * @see TypedArray#STYLE_ASSET_COOKIE 748 * @see TypedArray#STYLE_RESOURCE_ID 749 * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS 750 * @see TypedArray#STYLE_DENSITY 751 */ getResourceArray(@rrayRes int resId, @NonNull int[] outData)752 int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) { 753 Objects.requireNonNull(outData, "outData"); 754 synchronized (this) { 755 ensureValidLocked(); 756 return nativeGetResourceArray(mObject, resId, outData); 757 } 758 } 759 760 /** 761 * Retrieves the string array associated with a particular resource 762 * identifier for the current configuration. 763 * 764 * @param resId the resource identifier of the string array 765 * @return the string array, or {@code null} 766 */ getResourceStringArray(@rrayRes int resId)767 @Nullable String[] getResourceStringArray(@ArrayRes int resId) { 768 synchronized (this) { 769 ensureValidLocked(); 770 return nativeGetResourceStringArray(mObject, resId); 771 } 772 } 773 774 /** 775 * Retrieve the text array associated with a particular resource 776 * identifier. 777 * 778 * @param resId the resource id of the string array 779 */ getResourceTextArray(@rrayRes int resId)780 @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) { 781 synchronized (this) { 782 ensureValidLocked(); 783 final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId); 784 if (rawInfoArray == null) { 785 return null; 786 } 787 788 final int rawInfoArrayLen = rawInfoArray.length; 789 final int infoArrayLen = rawInfoArrayLen / 2; 790 final CharSequence[] retArray = new CharSequence[infoArrayLen]; 791 for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) { 792 int cookie = rawInfoArray[i]; 793 int index = rawInfoArray[i + 1]; 794 retArray[j] = (index >= 0 && cookie > 0) 795 ? getPooledStringForCookie(cookie, index) : null; 796 } 797 return retArray; 798 } 799 } 800 getResourceIntArray(@rrayRes int resId)801 @Nullable int[] getResourceIntArray(@ArrayRes int resId) { 802 synchronized (this) { 803 ensureValidLocked(); 804 return nativeGetResourceIntArray(mObject, resId); 805 } 806 } 807 808 /** 809 * Get the attributes for a style resource. These are the <item> 810 * elements in 811 * a <style> resource. 812 * @param resId The resource ID of the style 813 * @return An array of attribute IDs. 814 */ getStyleAttributes(@tyleRes int resId)815 @AttrRes int[] getStyleAttributes(@StyleRes int resId) { 816 synchronized (this) { 817 ensureValidLocked(); 818 return nativeGetStyleAttributes(mObject, resId); 819 } 820 } 821 822 /** 823 * Populates {@code outValue} with the data associated with a particular 824 * resource identifier for the current configuration. Resolves theme 825 * attributes against the specified theme. 826 * 827 * @param theme the native pointer of the theme 828 * @param resId the resource identifier to load 829 * @param outValue the typed value in which to put the data 830 * @param resolveRefs {@code true} to resolve references, {@code false} 831 * to leave them unresolved 832 * @return {@code true} if the data was loaded into {@code outValue}, 833 * {@code false} otherwise 834 */ getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, boolean resolveRefs)835 boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, 836 boolean resolveRefs) { 837 Objects.requireNonNull(outValue, "outValue"); 838 synchronized (this) { 839 ensureValidLocked(); 840 final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue, 841 resolveRefs); 842 if (cookie <= 0) { 843 return false; 844 } 845 846 // Convert the changing configurations flags populated by native code. 847 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 848 outValue.changingConfigurations); 849 850 if (outValue.type == TypedValue.TYPE_STRING) { 851 if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) { 852 return false; 853 } 854 } 855 return true; 856 } 857 } 858 dumpTheme(long theme, int priority, String tag, String prefix)859 void dumpTheme(long theme, int priority, String tag, String prefix) { 860 synchronized (this) { 861 ensureValidLocked(); 862 nativeThemeDump(mObject, theme, priority, tag, prefix); 863 } 864 } 865 866 @UnsupportedAppUsage getResourceName(@nyRes int resId)867 @Nullable String getResourceName(@AnyRes int resId) { 868 synchronized (this) { 869 ensureValidLocked(); 870 return nativeGetResourceName(mObject, resId); 871 } 872 } 873 874 @UnsupportedAppUsage getResourcePackageName(@nyRes int resId)875 @Nullable String getResourcePackageName(@AnyRes int resId) { 876 synchronized (this) { 877 ensureValidLocked(); 878 return nativeGetResourcePackageName(mObject, resId); 879 } 880 } 881 882 @UnsupportedAppUsage getResourceTypeName(@nyRes int resId)883 @Nullable String getResourceTypeName(@AnyRes int resId) { 884 synchronized (this) { 885 ensureValidLocked(); 886 return nativeGetResourceTypeName(mObject, resId); 887 } 888 } 889 890 @UnsupportedAppUsage getResourceEntryName(@nyRes int resId)891 @Nullable String getResourceEntryName(@AnyRes int resId) { 892 synchronized (this) { 893 ensureValidLocked(); 894 return nativeGetResourceEntryName(mObject, resId); 895 } 896 } 897 898 @UnsupportedAppUsage getResourceIdentifier(@onNull String name, @Nullable String defType, @Nullable String defPackage)899 @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType, 900 @Nullable String defPackage) { 901 synchronized (this) { 902 ensureValidLocked(); 903 // name is checked in JNI. 904 return nativeGetResourceIdentifier(mObject, name, defType, defPackage); 905 } 906 } 907 908 /** 909 * To get the parent theme resource id according to the parameter theme resource id. 910 * @param resId theme resource id. 911 * @return the parent theme resource id. 912 * @hide 913 */ 914 @StyleRes getParentThemeIdentifier(@tyleRes int resId)915 int getParentThemeIdentifier(@StyleRes int resId) { 916 synchronized (this) { 917 ensureValidLocked(); 918 // name is checked in JNI. 919 return nativeGetParentThemeIdentifier(mObject, resId); 920 } 921 } 922 923 /** 924 * Enable resource resolution logging to track the steps taken to resolve the last resource 925 * entry retrieved. Stores the configuration and package names for each step. 926 * 927 * Default disabled. 928 * 929 * @param enabled Boolean indicating whether to enable or disable logging. 930 * 931 * @hide 932 */ 933 @TestApi setResourceResolutionLoggingEnabled(boolean enabled)934 public void setResourceResolutionLoggingEnabled(boolean enabled) { 935 synchronized (this) { 936 ensureValidLocked(); 937 nativeSetResourceResolutionLoggingEnabled(mObject, enabled); 938 } 939 } 940 941 /** 942 * Retrieve the last resource resolution path logged. 943 * 944 * @return Formatted string containing last resource ID/name and steps taken to resolve final 945 * entry, including configuration and package names. 946 * 947 * @hide 948 */ 949 @TestApi getLastResourceResolution()950 public @Nullable String getLastResourceResolution() { 951 synchronized (this) { 952 ensureValidLocked(); 953 return nativeGetLastResourceResolution(mObject); 954 } 955 } 956 957 /** 958 * Returns whether the {@code resources.arsc} of any loaded apk assets is allocated in RAM 959 * (not mmapped). 960 * 961 * @hide 962 */ containsAllocatedTable()963 public boolean containsAllocatedTable() { 964 synchronized (this) { 965 ensureValidLocked(); 966 return nativeContainsAllocatedTable(mObject); 967 } 968 } 969 970 @Nullable getPooledStringForCookie(int cookie, int id)971 CharSequence getPooledStringForCookie(int cookie, int id) { 972 // Cookies map to ApkAssets starting at 1. 973 return getApkAssets()[cookie - 1].getStringFromPool(id); 974 } 975 976 /** 977 * Open an asset using ACCESS_STREAMING mode. This provides access to 978 * files that have been bundled with an application as assets -- that is, 979 * files placed in to the "assets" directory. 980 * 981 * @param fileName The name of the asset to open. This name can be hierarchical. 982 * 983 * @see #open(String, int) 984 * @see #list 985 */ open(@onNull String fileName)986 public @NonNull InputStream open(@NonNull String fileName) throws IOException { 987 return open(fileName, ACCESS_STREAMING); 988 } 989 990 /** 991 * Open an asset using an explicit access mode, returning an InputStream to 992 * read its contents. This provides access to files that have been bundled 993 * with an application as assets -- that is, files placed in to the 994 * "assets" directory. 995 * 996 * @param fileName The name of the asset to open. This name can be hierarchical. 997 * @param accessMode Desired access mode for retrieving the data. 998 * 999 * @see #ACCESS_UNKNOWN 1000 * @see #ACCESS_STREAMING 1001 * @see #ACCESS_RANDOM 1002 * @see #ACCESS_BUFFER 1003 * @see #open(String) 1004 * @see #list 1005 */ open(@onNull String fileName, int accessMode)1006 public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException { 1007 Objects.requireNonNull(fileName, "fileName"); 1008 synchronized (this) { 1009 ensureOpenLocked(); 1010 final long asset = nativeOpenAsset(mObject, fileName, accessMode); 1011 if (asset == 0) { 1012 throw new FileNotFoundException("Asset file: " + fileName); 1013 } 1014 final AssetInputStream assetInputStream = new AssetInputStream(asset); 1015 incRefsLocked(assetInputStream.hashCode()); 1016 return assetInputStream; 1017 } 1018 } 1019 1020 /** 1021 * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}. 1022 * This provides access to files that have been bundled with an application as assets -- that 1023 * is, files placed in to the "assets" directory. 1024 * 1025 * The asset must be uncompressed, or an exception will be thrown. 1026 * 1027 * @param fileName The name of the asset to open. This name can be hierarchical. 1028 * @return An open AssetFileDescriptor. 1029 */ openFd(@onNull String fileName)1030 public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException { 1031 Objects.requireNonNull(fileName, "fileName"); 1032 synchronized (this) { 1033 ensureOpenLocked(); 1034 final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets); 1035 if (pfd == null) { 1036 throw new FileNotFoundException("Asset file: " + fileName); 1037 } 1038 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 1039 } 1040 } 1041 1042 /** 1043 * Return a String array of all the assets at the given path. 1044 * 1045 * @param path A relative path within the assets, i.e., "docs/home.html". 1046 * 1047 * @return String[] Array of strings, one for each asset. These file 1048 * names are relative to 'path'. You can open the file by 1049 * concatenating 'path' and a name in the returned string (via 1050 * File) and passing that to open(). 1051 * 1052 * @see #open 1053 */ list(@onNull String path)1054 public @Nullable String[] list(@NonNull String path) throws IOException { 1055 Objects.requireNonNull(path, "path"); 1056 synchronized (this) { 1057 ensureValidLocked(); 1058 return nativeList(mObject, path); 1059 } 1060 } 1061 1062 /** 1063 * Open a non-asset file as an asset using ACCESS_STREAMING mode. This 1064 * provides direct access to all of the files included in an application 1065 * package (not only its assets). Applications should not normally use 1066 * this. 1067 * 1068 * @param fileName Name of the asset to retrieve. 1069 * 1070 * @see #open(String) 1071 * @hide 1072 */ 1073 @UnsupportedAppUsage openNonAsset(@onNull String fileName)1074 public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException { 1075 return openNonAsset(0, fileName, ACCESS_STREAMING); 1076 } 1077 1078 /** 1079 * Open a non-asset file as an asset using a specific access mode. This 1080 * provides direct access to all of the files included in an application 1081 * package (not only its assets). Applications should not normally use 1082 * this. 1083 * 1084 * @param fileName Name of the asset to retrieve. 1085 * @param accessMode Desired access mode for retrieving the data. 1086 * 1087 * @see #ACCESS_UNKNOWN 1088 * @see #ACCESS_STREAMING 1089 * @see #ACCESS_RANDOM 1090 * @see #ACCESS_BUFFER 1091 * @see #open(String, int) 1092 * @hide 1093 */ 1094 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) openNonAsset(@onNull String fileName, int accessMode)1095 public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode) 1096 throws IOException { 1097 return openNonAsset(0, fileName, accessMode); 1098 } 1099 1100 /** 1101 * Open a non-asset in a specified package. Not for use by applications. 1102 * 1103 * @param cookie Identifier of the package to be opened. 1104 * @param fileName Name of the asset to retrieve. 1105 * @hide 1106 */ 1107 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) openNonAsset(int cookie, @NonNull String fileName)1108 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName) 1109 throws IOException { 1110 return openNonAsset(cookie, fileName, ACCESS_STREAMING); 1111 } 1112 1113 /** 1114 * Open a non-asset in a specified package. Not for use by applications. 1115 * 1116 * @param cookie Identifier of the package to be opened. 1117 * @param fileName Name of the asset to retrieve. 1118 * @param accessMode Desired access mode for retrieving the data. 1119 * @hide 1120 */ 1121 @UnsupportedAppUsage openNonAsset(int cookie, @NonNull String fileName, int accessMode)1122 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode) 1123 throws IOException { 1124 Objects.requireNonNull(fileName, "fileName"); 1125 synchronized (this) { 1126 ensureOpenLocked(); 1127 final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode); 1128 if (asset == 0) { 1129 throw new FileNotFoundException("Asset absolute file: " + fileName); 1130 } 1131 final AssetInputStream assetInputStream = new AssetInputStream(asset); 1132 incRefsLocked(assetInputStream.hashCode()); 1133 return assetInputStream; 1134 } 1135 } 1136 1137 /** 1138 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 1139 * This provides direct access to all of the files included in an application 1140 * package (not only its assets). Applications should not normally use this. 1141 * 1142 * The asset must not be compressed, or an exception will be thrown. 1143 * 1144 * @param fileName Name of the asset to retrieve. 1145 */ openNonAssetFd(@onNull String fileName)1146 public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName) 1147 throws IOException { 1148 return openNonAssetFd(0, fileName); 1149 } 1150 1151 /** 1152 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 1153 * This provides direct access to all of the files included in an application 1154 * package (not only its assets). Applications should not normally use this. 1155 * 1156 * The asset must not be compressed, or an exception will be thrown. 1157 * 1158 * @param cookie Identifier of the package to be opened. 1159 * @param fileName Name of the asset to retrieve. 1160 */ openNonAssetFd(int cookie, @NonNull String fileName)1161 public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName) 1162 throws IOException { 1163 Objects.requireNonNull(fileName, "fileName"); 1164 synchronized (this) { 1165 ensureOpenLocked(); 1166 final ParcelFileDescriptor pfd = 1167 nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets); 1168 if (pfd == null) { 1169 throw new FileNotFoundException("Asset absolute file: " + fileName); 1170 } 1171 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 1172 } 1173 } 1174 1175 /** 1176 * Retrieve a parser for a compiled XML file. 1177 * 1178 * @param fileName The name of the file to retrieve. 1179 */ openXmlResourceParser(@onNull String fileName)1180 public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName) 1181 throws IOException { 1182 return openXmlResourceParser(0, fileName); 1183 } 1184 1185 /** 1186 * Retrieve a parser for a compiled XML file. 1187 * 1188 * @param cookie Identifier of the package to be opened. 1189 * @param fileName The name of the file to retrieve. 1190 */ openXmlResourceParser(int cookie, @NonNull String fileName)1191 public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName) 1192 throws IOException { 1193 try (XmlBlock block = openXmlBlockAsset(cookie, fileName, true)) { 1194 XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); 1195 // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with 1196 // a valid native pointer, which makes newParser always return non-null. But let's 1197 // be careful. 1198 if (parser == null) { 1199 throw new AssertionError("block.newParser() returned a null parser"); 1200 } 1201 return parser; 1202 } 1203 } 1204 1205 /** 1206 * Retrieve a non-asset as a compiled XML file. Not for use by applications. 1207 * 1208 * @param fileName The name of the file to retrieve. 1209 * @hide 1210 */ openXmlBlockAsset(@onNull String fileName)1211 @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException { 1212 return openXmlBlockAsset(0, fileName, true); 1213 } 1214 1215 /** 1216 * Retrieve a non-asset as a compiled XML file. Not for use by 1217 * applications. 1218 * 1219 * @param cookie Identifier of the package to be opened. 1220 * @param fileName Name of the asset to retrieve. 1221 * @param usesFeatureFlags Whether the resources uses feature flags 1222 * @hide 1223 */ openXmlBlockAsset(int cookie, @NonNull String fileName, boolean usesFeatureFlags)1224 @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName, 1225 boolean usesFeatureFlags) throws IOException { 1226 Objects.requireNonNull(fileName, "fileName"); 1227 synchronized (this) { 1228 ensureOpenLocked(); 1229 1230 final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName); 1231 if (xmlBlock == 0) { 1232 throw new FileNotFoundException("Asset XML file: " + fileName); 1233 } 1234 1235 final XmlBlock block = new XmlBlock(this, xmlBlock, usesFeatureFlags); 1236 incRefsLocked(block.hashCode()); 1237 return block; 1238 } 1239 } 1240 xmlBlockGone(int id)1241 void xmlBlockGone(int id) { 1242 decRefs(id); 1243 } 1244 1245 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 1246 @RavenwoodReplace applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1247 void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1248 @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, 1249 long outIndicesAddress) { 1250 Objects.requireNonNull(inAttrs, "inAttrs"); 1251 synchronized (this) { 1252 // Need to synchronize on AssetManager because we will be accessing 1253 // the native implementation of AssetManager. 1254 ensureValidLocked(); 1255 nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes, 1256 parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress, 1257 outIndicesAddress); 1258 } 1259 } 1260 getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @StyleRes int xmlStyle)1261 int[] getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, 1262 @StyleRes int defStyleRes, @StyleRes int xmlStyle) { 1263 synchronized (this) { 1264 ensureValidLocked(); 1265 return nativeAttributeResolutionStack( 1266 mObject, themePtr, xmlStyle, defStyleAttr, defStyleRes); 1267 } 1268 } 1269 1270 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1271 boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1272 @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, 1273 @NonNull int[] outIndices) { 1274 Objects.requireNonNull(inAttrs, "inAttrs"); 1275 Objects.requireNonNull(outValues, "outValues"); 1276 Objects.requireNonNull(outIndices, "outIndices"); 1277 synchronized (this) { 1278 // Need to synchronize on AssetManager because we will be accessing 1279 // the native implementation of AssetManager. 1280 ensureValidLocked(); 1281 return nativeResolveAttrs(mObject, 1282 themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices); 1283 } 1284 } 1285 1286 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveAttributes(@onNull XmlBlock.Parser parser, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1287 boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs, 1288 @NonNull int[] outValues, @NonNull int[] outIndices) { 1289 Objects.requireNonNull(parser, "parser"); 1290 Objects.requireNonNull(inAttrs, "inAttrs"); 1291 Objects.requireNonNull(outValues, "outValues"); 1292 Objects.requireNonNull(outIndices, "outIndices"); 1293 synchronized (this) { 1294 // Need to synchronize on AssetManager because we will be accessing 1295 // the native implementation of AssetManager. 1296 ensureValidLocked(); 1297 return nativeRetrieveAttributes( 1298 mObject, parser.mParseState, inAttrs, outValues, outIndices); 1299 } 1300 } 1301 1302 @UnsupportedAppUsage createTheme()1303 long createTheme() { 1304 synchronized (this) { 1305 ensureValidLocked(); 1306 long themePtr = nativeThemeCreate(mObject); 1307 incRefsLocked(themePtr); 1308 return themePtr; 1309 } 1310 } 1311 releaseTheme(long themePtr)1312 void releaseTheme(long themePtr) { 1313 decRefs(themePtr); 1314 } 1315 getThemeFreeFunction()1316 static long getThemeFreeFunction() { 1317 return nativeGetThemeFreeFunction(); 1318 } 1319 applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force)1320 void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) { 1321 synchronized (this) { 1322 // Need to synchronize on AssetManager because we will be accessing 1323 // the native implementation of AssetManager. 1324 ensureValidLocked(); 1325 nativeThemeApplyStyle(mObject, themePtr, resId, force); 1326 } 1327 } 1328 rebaseTheme(long themePtr, @NonNull AssetManager newAssetManager, @StyleRes int[] styleIds, @StyleRes boolean[] force, int count)1329 AssetManager rebaseTheme(long themePtr, @NonNull AssetManager newAssetManager, 1330 @StyleRes int[] styleIds, @StyleRes boolean[] force, int count) { 1331 // Exchange ownership of the theme with the new asset manager. 1332 if (this != newAssetManager) { 1333 synchronized (this) { 1334 ensureValidLocked(); 1335 decRefs(themePtr); 1336 } 1337 synchronized (newAssetManager) { 1338 newAssetManager.ensureValidLocked(); 1339 newAssetManager.incRefsLocked(themePtr); 1340 } 1341 } 1342 1343 try { 1344 synchronized (newAssetManager) { 1345 newAssetManager.ensureValidLocked(); 1346 nativeThemeRebase(newAssetManager.mObject, themePtr, styleIds, force, count); 1347 } 1348 } finally { 1349 Reference.reachabilityFence(newAssetManager); 1350 } 1351 return newAssetManager; 1352 } 1353 1354 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr)1355 void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) { 1356 synchronized (this) { 1357 ensureValidLocked(); 1358 synchronized (srcAssetManager) { 1359 srcAssetManager.ensureValidLocked(); 1360 nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr); 1361 } 1362 } 1363 } 1364 1365 @Override finalize()1366 protected void finalize() throws Throwable { 1367 if (DEBUG_REFS && mNumRefs.get() != 0) { 1368 Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs.get()); 1369 if (mRefStacks != null) { 1370 for (RuntimeException e : mRefStacks.values()) { 1371 Log.w(TAG, "Reference from here", e); 1372 } 1373 } 1374 } 1375 1376 synchronized (this) { 1377 if (mObject != 0) { 1378 nativeDestroy(mObject); 1379 mObject = 0; 1380 } 1381 } 1382 } 1383 1384 /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread 1385 safe and it does not rely on AssetManager once it has been created. It completely owns the 1386 underlying Asset. */ 1387 public final class AssetInputStream extends InputStream { 1388 private long mAssetNativePtr; 1389 private long mLength; 1390 private long mMarkPos; 1391 1392 /** 1393 * @hide 1394 */ 1395 @UnsupportedAppUsage getAssetInt()1396 public final int getAssetInt() { 1397 throw new UnsupportedOperationException(); 1398 } 1399 1400 /** 1401 * @hide 1402 */ 1403 @UnsupportedAppUsage getNativeAsset()1404 public final long getNativeAsset() { 1405 return mAssetNativePtr; 1406 } 1407 AssetInputStream(long assetNativePtr)1408 private AssetInputStream(long assetNativePtr) { 1409 mAssetNativePtr = assetNativePtr; 1410 mLength = nativeAssetGetLength(assetNativePtr); 1411 } 1412 1413 @Override read()1414 public final int read() throws IOException { 1415 ensureOpen(); 1416 return nativeAssetReadChar(mAssetNativePtr); 1417 } 1418 1419 @Override read(@onNull byte[] b)1420 public final int read(@NonNull byte[] b) throws IOException { 1421 ensureOpen(); 1422 Objects.requireNonNull(b, "b"); 1423 return nativeAssetRead(mAssetNativePtr, b, 0, b.length); 1424 } 1425 1426 @Override read(@onNull byte[] b, int off, int len)1427 public final int read(@NonNull byte[] b, int off, int len) throws IOException { 1428 ensureOpen(); 1429 Objects.requireNonNull(b, "b"); 1430 return nativeAssetRead(mAssetNativePtr, b, off, len); 1431 } 1432 1433 @Override skip(long n)1434 public final long skip(long n) throws IOException { 1435 ensureOpen(); 1436 long pos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1437 if ((pos + n) > mLength) { 1438 n = mLength - pos; 1439 } 1440 if (n > 0) { 1441 nativeAssetSeek(mAssetNativePtr, n, 0); 1442 } 1443 return n; 1444 } 1445 1446 @Override available()1447 public final int available() throws IOException { 1448 ensureOpen(); 1449 final long len = nativeAssetGetRemainingLength(mAssetNativePtr); 1450 return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len; 1451 } 1452 1453 @Override markSupported()1454 public final boolean markSupported() { 1455 return true; 1456 } 1457 1458 @Override mark(int readlimit)1459 public final void mark(int readlimit) { 1460 ensureOpen(); 1461 mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1462 } 1463 1464 @Override reset()1465 public final void reset() throws IOException { 1466 ensureOpen(); 1467 nativeAssetSeek(mAssetNativePtr, mMarkPos, -1); 1468 } 1469 1470 @Override close()1471 public final void close() throws IOException { 1472 if (mAssetNativePtr != 0) { 1473 nativeAssetDestroy(mAssetNativePtr); 1474 mAssetNativePtr = 0; 1475 1476 decRefs(hashCode()); 1477 } 1478 } 1479 1480 @Override finalize()1481 protected void finalize() throws Throwable { 1482 close(); 1483 } 1484 ensureOpen()1485 private void ensureOpen() { 1486 if (mAssetNativePtr == 0) { 1487 throw new IllegalStateException("AssetInputStream is closed"); 1488 } 1489 } 1490 } 1491 1492 /** 1493 * Determine whether the state in this asset manager is up-to-date with 1494 * the files on the filesystem. If false is returned, you need to 1495 * instantiate a new AssetManager class to see the new data. 1496 * @hide 1497 */ 1498 @UnsupportedAppUsage isUpToDate()1499 public boolean isUpToDate() { 1500 synchronized (this) { 1501 if (!mOpen) { 1502 return false; 1503 } 1504 1505 for (ApkAssets apkAssets : mApkAssets) { 1506 if (!apkAssets.isUpToDate()) { 1507 return false; 1508 } 1509 } 1510 1511 return true; 1512 } 1513 } 1514 1515 /** 1516 * Get the locales that this asset manager contains data for. 1517 * 1518 * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid 1519 * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be 1520 * parsed using {@link Locale#forLanguageTag(String)}. 1521 * 1522 * <p>On SDK 20 (Android 4.4W: KitKat for watches) and below, locale strings 1523 * are of the form {@code ll_CC} where {@code ll} is a two letter language code, 1524 * and {@code CC} is a two letter country code. 1525 */ getLocales()1526 public String[] getLocales() { 1527 synchronized (this) { 1528 ensureValidLocked(); 1529 return nativeGetLocales(mObject, false /*excludeSystem*/); 1530 } 1531 } 1532 1533 /** 1534 * Same as getLocales(), except that locales that are only provided by the system (i.e. those 1535 * present in framework-res.apk or its overlays) will not be listed. 1536 * 1537 * For example, if the "system" assets support English, French, and German, and the additional 1538 * assets support Cherokee and French, getLocales() would return 1539 * [Cherokee, English, French, German], while getNonSystemLocales() would return 1540 * [Cherokee, French]. 1541 * @hide 1542 */ getNonSystemLocales()1543 public String[] getNonSystemLocales() { 1544 synchronized (this) { 1545 ensureValidLocked(); 1546 return nativeGetLocales(mObject, true /*excludeSystem*/); 1547 } 1548 } 1549 1550 /** 1551 * @hide 1552 */ getSizeConfigurations()1553 Configuration[] getSizeConfigurations() { 1554 synchronized (this) { 1555 ensureValidLocked(); 1556 return nativeGetSizeConfigurations(mObject); 1557 } 1558 } 1559 1560 /** 1561 * @hide 1562 */ getSizeAndUiModeConfigurations()1563 Configuration[] getSizeAndUiModeConfigurations() { 1564 synchronized (this) { 1565 ensureValidLocked(); 1566 return nativeGetSizeAndUiModeConfigurations(mObject); 1567 } 1568 } 1569 1570 /** 1571 * Change the configuration used when retrieving resources. Not for use by 1572 * applications. 1573 * @hide 1574 */ 1575 @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 grammaticalGender, int majorVersion)1576 public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation, 1577 int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, 1578 int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, 1579 int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, 1580 int majorVersion) { 1581 if (locale != null) { 1582 setConfiguration(mcc, mnc, null, new String[]{locale}, orientation, touchscreen, 1583 density, keyboard, keyboardHidden, navigation, screenWidth, screenHeight, 1584 smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, 1585 colorMode, grammaticalGender, majorVersion); 1586 } else { 1587 setConfiguration(mcc, mnc, null, null, orientation, touchscreen, density, 1588 keyboard, keyboardHidden, navigation, screenWidth, screenHeight, 1589 smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, 1590 colorMode, grammaticalGender, majorVersion); 1591 } 1592 } 1593 1594 /** 1595 * Change the configuration used when retrieving resources. Not for use by 1596 * applications. 1597 * @hide 1598 */ setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales, 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 grammaticalGender, int majorVersion)1599 public void setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales, 1600 int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, 1601 int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, 1602 int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, 1603 int grammaticalGender, int majorVersion) { 1604 setConfigurationInternal(mcc, mnc, defaultLocale, locales, orientation, 1605 touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth, 1606 screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, 1607 screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, false); 1608 } 1609 1610 /** 1611 * Change the configuration used when retrieving resources, and potentially force a refresh of 1612 * the state. Not for use by applications. 1613 * @hide 1614 */ setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales, 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 grammaticalGender, int majorVersion, boolean forceRefresh)1615 void setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales, 1616 int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, 1617 int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, 1618 int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, 1619 int grammaticalGender, int majorVersion, boolean forceRefresh) { 1620 synchronized (this) { 1621 ensureValidLocked(); 1622 nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation, 1623 touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth, 1624 screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, 1625 screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, 1626 forceRefresh); 1627 } 1628 } 1629 1630 /** 1631 * Passes the display id and device id to AssetManager, to filter out overlays based on 1632 * any {@link android.content.om.OverlayConstraint}. 1633 * 1634 * @hide 1635 */ setOverlayConstraints(int displayId, int deviceId)1636 public void setOverlayConstraints(int displayId, int deviceId) { 1637 if (!Flags.rroConstraints()) { 1638 return; 1639 } 1640 1641 synchronized (this) { 1642 ensureValidLocked(); 1643 nativeSetOverlayConstraints(mObject, displayId, deviceId); 1644 } 1645 } 1646 1647 /** 1648 * @hide 1649 */ 1650 @UnsupportedAppUsage getAssignedPackageIdentifiers()1651 public SparseArray<String> getAssignedPackageIdentifiers() { 1652 return getAssignedPackageIdentifiers(true, true); 1653 } 1654 1655 /** 1656 * @hide 1657 */ getAssignedPackageIdentifiers(boolean includeOverlays, boolean includeLoaders)1658 public SparseArray<String> getAssignedPackageIdentifiers(boolean includeOverlays, 1659 boolean includeLoaders) { 1660 synchronized (this) { 1661 ensureValidLocked(); 1662 return nativeGetAssignedPackageIdentifiers(mObject, includeOverlays, includeLoaders); 1663 } 1664 } 1665 1666 /** 1667 * @hide 1668 */ 1669 @GuardedBy("this") getOverlayableMap(String packageName)1670 public @Nullable Map<String, String> getOverlayableMap(String packageName) { 1671 synchronized (this) { 1672 ensureValidLocked(); 1673 return nativeGetOverlayableMap(mObject, packageName); 1674 } 1675 } 1676 1677 /** 1678 * @hide 1679 */ 1680 @TestApi 1681 @GuardedBy("this") getOverlayablesToString(String packageName)1682 public @Nullable String getOverlayablesToString(String packageName) { 1683 synchronized (this) { 1684 ensureValidLocked(); 1685 return nativeGetOverlayablesToString(mObject, packageName); 1686 } 1687 } 1688 1689 @GuardedBy("this") incRefsLocked(long id)1690 private void incRefsLocked(long id) { 1691 if (DEBUG_REFS) { 1692 if (mRefStacks == null) { 1693 mRefStacks = new HashMap<>(); 1694 } 1695 RuntimeException ex = new RuntimeException(); 1696 mRefStacks.put(id, ex); 1697 } 1698 mNumRefs.incrementAndGet(); 1699 } 1700 decRefs(long id)1701 private void decRefs(long id) { 1702 if (DEBUG_REFS) { 1703 synchronized (this) { 1704 if (mRefStacks != null) { 1705 mRefStacks.remove(id); 1706 } 1707 } 1708 } 1709 if (mNumRefs.decrementAndGet() == 0) { 1710 synchronized (this) { 1711 if (mNumRefs.get() == 0 && mObject != 0) { 1712 nativeDestroy(mObject); 1713 mObject = 0; 1714 mApkAssets = sEmptyApkAssets; 1715 } 1716 } 1717 } 1718 } 1719 dump(PrintWriter pw, String prefix)1720 synchronized void dump(PrintWriter pw, String prefix) { 1721 pw.println(prefix + "class=" + getClass()); 1722 pw.println(prefix + "apkAssets="); 1723 for (int i = 0; i < mApkAssets.length; i++) { 1724 pw.println(prefix + i); 1725 mApkAssets[i].dump(pw, prefix + " "); 1726 } 1727 } 1728 1729 // AssetManager setup native methods. nativeCreate()1730 private static native long nativeCreate(); nativeDestroy(long ptr)1731 private static native void nativeDestroy(long ptr); nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, boolean invalidateCaches, boolean preset)1732 private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, 1733 boolean invalidateCaches, boolean preset); nativeSetConfiguration(long ptr, int mcc, int mnc, @Nullable String defaultLocale, @NonNull String[] locales, 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 grammaticalGender, int majorVersion, boolean forceRefresh)1734 private static native void nativeSetConfiguration(long ptr, int mcc, int mnc, 1735 @Nullable String defaultLocale, @NonNull String[] locales, int orientation, 1736 int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, 1737 int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, 1738 int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, 1739 int majorVersion, boolean forceRefresh); nativeSetOverlayConstraints(long ptr, int displayId, int deviceId)1740 private static native void nativeSetOverlayConstraints(long ptr, int displayId, int deviceId); nativeGetAssignedPackageIdentifiers( long ptr, boolean includeOverlays, boolean includeLoaders)1741 private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers( 1742 long ptr, boolean includeOverlays, boolean includeLoaders); 1743 1744 // File native methods. nativeContainsAllocatedTable(long ptr)1745 private static native boolean nativeContainsAllocatedTable(long ptr); nativeList(long ptr, @NonNull String path)1746 private static native @Nullable String[] nativeList(long ptr, @NonNull String path) 1747 throws IOException; nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode)1748 private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode); nativeOpenAssetFd(long ptr, @NonNull String fileName, long[] outOffsets)1749 private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr, 1750 @NonNull String fileName, long[] outOffsets) throws IOException; nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, int accessMode)1751 private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, 1752 int accessMode); nativeOpenNonAssetFd(long ptr, int cookie, @NonNull String fileName, @NonNull long[] outOffsets)1753 private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie, 1754 @NonNull String fileName, @NonNull long[] outOffsets) throws IOException; nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName)1755 private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName); nativeOpenXmlAssetFd(long ptr, int cookie, @NonNull FileDescriptor fileDescriptor)1756 private static native long nativeOpenXmlAssetFd(long ptr, int cookie, 1757 @NonNull FileDescriptor fileDescriptor); 1758 1759 // Primitive resource native methods. nativeGetResourceValue(long ptr, @AnyRes int resId, short density, @NonNull TypedValue outValue, boolean resolveReferences)1760 private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density, 1761 @NonNull TypedValue outValue, boolean resolveReferences); nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, @NonNull TypedValue outValue)1762 private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, 1763 @NonNull TypedValue outValue); 1764 nativeGetStyleAttributes(long ptr, @StyleRes int resId)1765 private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr, 1766 @StyleRes int resId); nativeGetResourceStringArray(long ptr, @ArrayRes int resId)1767 private static native @Nullable String[] nativeGetResourceStringArray(long ptr, 1768 @ArrayRes int resId); nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resId)1769 private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr, 1770 @ArrayRes int resId); nativeGetResourceIntArray(long ptr, @ArrayRes int resId)1771 private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId); nativeGetResourceArraySize(long ptr, @ArrayRes int resId)1772 private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId); nativeGetResourceArray(long ptr, @ArrayRes int resId, @NonNull int[] outValues)1773 private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId, 1774 @NonNull int[] outValues); 1775 1776 // Resource name/ID native methods. nativeGetResourceIdentifier(long ptr, @NonNull String name, @Nullable String defType, @Nullable String defPackage)1777 private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name, 1778 @Nullable String defType, @Nullable String defPackage); nativeGetResourceName(long ptr, @AnyRes int resid)1779 private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid); nativeGetResourcePackageName(long ptr, @AnyRes int resid)1780 private static native @Nullable String nativeGetResourcePackageName(long ptr, 1781 @AnyRes int resid); nativeGetResourceTypeName(long ptr, @AnyRes int resid)1782 private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid); nativeGetResourceEntryName(long ptr, @AnyRes int resid)1783 private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); nativeGetLocales(long ptr, boolean excludeSystem)1784 private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); nativeGetSizeConfigurations(long ptr)1785 private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); nativeGetSizeAndUiModeConfigurations(long ptr)1786 private static native @Nullable Configuration[] nativeGetSizeAndUiModeConfigurations(long ptr); nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled)1787 private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); nativeGetLastResourceResolution(long ptr)1788 private static native @Nullable String nativeGetLastResourceResolution(long ptr); 1789 1790 // Style attribute retrieval native methods. nativeAttributeResolutionStack(long ptr, long themePtr, @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)1791 private static native int[] nativeAttributeResolutionStack(long ptr, long themePtr, 1792 @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)1793 private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, 1794 @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, 1795 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)1796 private static native boolean nativeResolveAttrs(long ptr, long themePtr, 1797 @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, 1798 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); nativeRetrieveAttributes(long ptr, long xmlParserPtr, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1799 private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr, 1800 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); 1801 1802 // Theme related native methods nativeThemeCreate(long ptr)1803 private static native long nativeThemeCreate(long ptr); nativeGetThemeFreeFunction()1804 private static native long nativeGetThemeFreeFunction(); nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, boolean force)1805 private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, 1806 boolean force); nativeThemeRebase(long ptr, long themePtr, @NonNull int[] styleIds, @NonNull boolean[] force, int styleSize)1807 private static native void nativeThemeRebase(long ptr, long themePtr, @NonNull int[] styleIds, 1808 @NonNull boolean[] force, int styleSize); nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, long srcAssetManagerPtr, long srcThemePtr)1809 private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, 1810 long srcAssetManagerPtr, long srcThemePtr); nativeThemeGetAttributeValue(long ptr, long themePtr, @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve)1811 private static native int nativeThemeGetAttributeValue(long ptr, long themePtr, 1812 @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve); nativeThemeDump(long ptr, long themePtr, int priority, String tag, String prefix)1813 private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag, 1814 String prefix); nativeThemeGetChangingConfigurations(long themePtr)1815 static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr); 1816 @StyleRes nativeGetParentThemeIdentifier(long ptr, @StyleRes int styleId)1817 private static native int nativeGetParentThemeIdentifier(long ptr, @StyleRes int styleId); 1818 1819 // AssetInputStream related native methods. nativeAssetDestroy(long assetPtr)1820 private static native void nativeAssetDestroy(long assetPtr); nativeAssetReadChar(long assetPtr)1821 private static native int nativeAssetReadChar(long assetPtr); nativeAssetRead(long assetPtr, byte[] b, int off, int len)1822 private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len); nativeAssetSeek(long assetPtr, long offset, int whence)1823 private static native long nativeAssetSeek(long assetPtr, long offset, int whence); nativeAssetGetLength(long assetPtr)1824 private static native long nativeAssetGetLength(long assetPtr); nativeAssetGetRemainingLength(long assetPtr)1825 private static native long nativeAssetGetRemainingLength(long assetPtr); 1826 nativeGetOverlayableMap(long ptr, @NonNull String packageName)1827 private static native @Nullable Map nativeGetOverlayableMap(long ptr, 1828 @NonNull String packageName); nativeGetOverlayablesToString(long ptr, @NonNull String packageName)1829 private static native @Nullable String nativeGetOverlayablesToString(long ptr, 1830 @NonNull String packageName); 1831 1832 // Global debug native methods. 1833 /** 1834 * @hide 1835 */ 1836 @UnsupportedAppUsage getGlobalAssetCount()1837 public static native int getGlobalAssetCount(); 1838 1839 /** 1840 * @hide 1841 */ getAssetAllocations()1842 public static native String getAssetAllocations(); 1843 1844 /** 1845 * @hide 1846 */ 1847 @UnsupportedAppUsage getGlobalAssetManagerCount()1848 public static native int getGlobalAssetManagerCount(); 1849 1850 // Ravenwood Workarounds 1851 1852 /** 1853 * ART has explicit support for allocating pinned (non-movable) array objects. 1854 * On Ravenwood we allocate regular arrays and use critical array access in 1855 * JNI as a best effort to reduce memory copying. 1856 * TODO(b/359983716): Remove when Ravenwood switch to ART 1857 */ applyStyle$ravenwood(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1858 void applyStyle$ravenwood(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1859 @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, 1860 long outIndicesAddress) { 1861 Objects.requireNonNull(inAttrs, "inAttrs"); 1862 var runtime = RavenwoodEnvironment.getInstance(); 1863 final int[] outValues = runtime.fromAddress(outValuesAddress); 1864 final int[] outIndices = runtime.fromAddress(outIndicesAddress); 1865 synchronized (this) { 1866 // Need to synchronize on AssetManager because we will be accessing 1867 // the native implementation of AssetManager. 1868 ensureValidLocked(); 1869 nativeApplyStyleWithArray(mObject, themePtr, defStyleAttr, defStyleRes, 1870 parser != null ? parser.mParseState : 0, inAttrs, outValues, 1871 outIndices); 1872 } 1873 } 1874 1875 /** 1876 * A variant of nativeApplyStyle(), accepting java arrays instead of raw pointers. 1877 * TODO(b/359983716): Remove when Ravenwood switch to ART 1878 */ nativeApplyStyleWithArray(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, int[] outData, int[] outIndices)1879 private static native void nativeApplyStyleWithArray(long ptr, long themePtr, 1880 @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1881 long xmlParserPtr, @NonNull int[] inAttrs, int[] outData, int[] outIndices); 1882 } 1883