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