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