Home | History | Annotate | Download | only in res
      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 
    119         public Builder addApkAssets(ApkAssets apkAssets) {
    120             mUserApkAssets.add(apkAssets);
    121             return this;
    122         }
    123 
    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      */
    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")
    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")
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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
    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
    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
    383     public int addOverlayPath(String path) {
    384         return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
    385     }
    386 
    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")
    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")
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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 
    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 
    668     @Nullable String getResourceName(@AnyRes int resId) {
    669         synchronized (this) {
    670             ensureValidLocked();
    671             return nativeGetResourceName(mObject, resId);
    672         }
    673     }
    674 
    675     @Nullable String getResourcePackageName(@AnyRes int resId) {
    676         synchronized (this) {
    677             ensureValidLocked();
    678             return nativeGetResourcePackageName(mObject, resId);
    679         }
    680     }
    681 
    682     @Nullable String getResourceTypeName(@AnyRes int resId) {
    683         synchronized (this) {
    684             ensureValidLocked();
    685             return nativeGetResourceTypeName(mObject, resId);
    686         }
    687     }
    688 
    689     @Nullable String getResourceEntryName(@AnyRes int resId) {
    690         synchronized (this) {
    691             ensureValidLocked();
    692             return nativeGetResourceEntryName(mObject, resId);
    693         }
    694     }
    695 
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    967     void xmlBlockGone(int id) {
    968         synchronized (this) {
    969             decRefsLocked(id);
    970         }
    971     }
    972 
    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 
    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 
   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 
   1017     long createTheme() {
   1018         synchronized (this) {
   1019             ensureValidLocked();
   1020             long themePtr = nativeThemeCreate(mObject);
   1021             incRefsLocked(themePtr);
   1022             return themePtr;
   1023         }
   1024     }
   1025 
   1026     void releaseTheme(long themePtr) {
   1027         synchronized (this) {
   1028             nativeThemeDestroy(themePtr);
   1029             decRefsLocked(themePtr);
   1030         }
   1031     }
   1032 
   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
   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          */
   1069         public final int getAssetInt() {
   1070             throw new UnsupportedOperationException();
   1071         }
   1072 
   1073         /**
   1074          * @hide
   1075          */
   1076         public final long getNativeAsset() {
   1077             return mAssetNativePtr;
   1078         }
   1079 
   1080         private AssetInputStream(long assetNativePtr) {
   1081             mAssetNativePtr = assetNativePtr;
   1082             mLength = nativeAssetGetLength(assetNativePtr);
   1083         }
   1084 
   1085         @Override
   1086         public final int read() throws IOException {
   1087             ensureOpen();
   1088             return nativeAssetReadChar(mAssetNativePtr);
   1089         }
   1090 
   1091         @Override
   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
   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
   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
   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
   1126         public final boolean markSupported() {
   1127             return true;
   1128         }
   1129 
   1130         @Override
   1131         public final void mark(int readlimit) {
   1132             ensureOpen();
   1133             mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0);
   1134         }
   1135 
   1136         @Override
   1137         public final void reset() throws IOException {
   1138             ensureOpen();
   1139             nativeAssetSeek(mAssetNativePtr, mMarkPos, -1);
   1140         }
   1141 
   1142         @Override
   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
   1155         protected void finalize() throws Throwable {
   1156             close();
   1157         }
   1158 
   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      */
   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      */
   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      */
   1209     public String[] getNonSystemLocales() {
   1210         synchronized (this) {
   1211             ensureValidLocked();
   1212             return nativeGetLocales(mObject, true /*excludeSystem*/);
   1213         }
   1214     }
   1215 
   1216     /**
   1217      * @hide
   1218      */
   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      */
   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      */
   1247     public SparseArray<String> getAssignedPackageIdentifiers() {
   1248         synchronized (this) {
   1249             ensureValidLocked();
   1250             return nativeGetAssignedPackageIdentifiers(mObject);
   1251         }
   1252     }
   1253 
   1254     @GuardedBy("this")
   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")
   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.
   1281     private static native long nativeCreate();
   1282     private static native void nativeDestroy(long ptr);
   1283     private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
   1284             boolean invalidateCaches);
   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);
   1290     private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
   1291             long ptr);
   1292 
   1293     // File native methods.
   1294     private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
   1295             throws IOException;
   1296     private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);
   1297     private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr,
   1298             @NonNull String fileName, long[] outOffsets) throws IOException;
   1299     private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName,
   1300             int accessMode);
   1301     private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie,
   1302             @NonNull String fileName, @NonNull long[] outOffsets) throws IOException;
   1303     private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName);
   1304 
   1305     // Primitive resource native methods.
   1306     private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density,
   1307             @NonNull TypedValue outValue, boolean resolveReferences);
   1308     private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId,
   1309             @NonNull TypedValue outValue);
   1310 
   1311     private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
   1312             @StyleRes int resId);
   1313     private static native @Nullable String[] nativeGetResourceStringArray(long ptr,
   1314             @ArrayRes int resId);
   1315     private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
   1316             @ArrayRes int resId);
   1317     private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId);
   1318     private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId);
   1319     private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId,
   1320             @NonNull int[] outValues);
   1321 
   1322     // Resource name/ID native methods.
   1323     private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
   1324             @Nullable String defType, @Nullable String defPackage);
   1325     private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid);
   1326     private static native @Nullable String nativeGetResourcePackageName(long ptr,
   1327             @AnyRes int resid);
   1328     private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid);
   1329     private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
   1330     private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
   1331     private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
   1332 
   1333     // Style attribute retrieval native methods.
   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);
   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);
   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
   1344     private static native long nativeThemeCreate(long ptr);
   1345     private static native void nativeThemeDestroy(long themePtr);
   1346     private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
   1347             boolean force);
   1348     static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
   1349     static native void nativeThemeClear(long themePtr);
   1350     private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
   1351             @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
   1352     private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
   1353             String prefix);
   1354     static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr);
   1355 
   1356     // AssetInputStream related native methods.
   1357     private static native void nativeAssetDestroy(long assetPtr);
   1358     private static native int nativeAssetReadChar(long assetPtr);
   1359     private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len);
   1360     private static native long nativeAssetSeek(long assetPtr, long offset, int whence);
   1361     private static native long nativeAssetGetLength(long assetPtr);
   1362     private static native long nativeAssetGetRemainingLength(long assetPtr);
   1363 
   1364     private static native void nativeVerifySystemIdmaps();
   1365 
   1366     // Global debug native methods.
   1367     /**
   1368      * @hide
   1369      */
   1370     public static native int getGlobalAssetCount();
   1371 
   1372     /**
   1373      * @hide
   1374      */
   1375     public static native String getAssetAllocations();
   1376 
   1377     /**
   1378      * @hide
   1379      */
   1380     public static native int getGlobalAssetManagerCount();
   1381 }
   1382