• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &lt;item&gt;
810      * elements in
811      * a &lt;style&gt; 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