Fix potential double destroy of AssetManager
Assume there is a XmlBlock [X] created by a AssetManager [A] ([A] will have mNumRefs = 2). After [A].close is called (mNumRefs = 1) and then both [X] and [A] are going to be GCed, if [A].finalize is called first (nativeDestroy), the later [X].finalize will invoke [A].xmlBlockGone that triggers the second nativeDestroy of [A] and leads to crash. By clearing the mObject in AssetManager.finalize, the decRefsLocked from other paths won't call nativeDestroy again. Bug: 144028297 Test: atest android.security.cts.AssetManagerTest Change-Id: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1 Merged-In: Ia938502d2443f5a6de6a3cabdb7ce1d41d3ff6d1
This commit is contained in:
@@ -68,24 +68,24 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
|
|
||||||
private static final String TAG = "AssetManager";
|
private static final String TAG = "AssetManager";
|
||||||
private static final boolean localLOGV = false || false;
|
private static final boolean localLOGV = false || false;
|
||||||
|
|
||||||
private static final boolean DEBUG_REFS = false;
|
private static final boolean DEBUG_REFS = false;
|
||||||
|
|
||||||
private static final Object sSync = new Object();
|
private static final Object sSync = new Object();
|
||||||
/*package*/ static AssetManager sSystem = null;
|
/*package*/ static AssetManager sSystem = null;
|
||||||
|
|
||||||
private final TypedValue mValue = new TypedValue();
|
private final TypedValue mValue = new TypedValue();
|
||||||
private final long[] mOffsets = new long[2];
|
private final long[] mOffsets = new long[2];
|
||||||
|
|
||||||
// For communication with native code.
|
// For communication with native code.
|
||||||
private long mObject;
|
private long mObject;
|
||||||
|
|
||||||
private StringBlock mStringBlocks[] = null;
|
private StringBlock mStringBlocks[] = null;
|
||||||
|
|
||||||
private int mNumRefs = 1;
|
private int mNumRefs = 1;
|
||||||
private boolean mOpen = true;
|
private boolean mOpen = true;
|
||||||
private HashMap<Long, RuntimeException> mRefStacks;
|
private HashMap<Long, RuntimeException> mRefStacks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new AssetManager containing only the basic system assets.
|
* Create a new AssetManager containing only the basic system assets.
|
||||||
* Applications will not generally use this method, instead retrieving the
|
* Applications will not generally use this method, instead retrieving the
|
||||||
@@ -114,7 +114,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssetManager(boolean isSystem) {
|
private AssetManager(boolean isSystem) {
|
||||||
if (DEBUG_REFS) {
|
if (DEBUG_REFS) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -337,10 +337,10 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* Open an asset using ACCESS_STREAMING mode. This provides access to
|
* Open an asset using ACCESS_STREAMING mode. This provides access to
|
||||||
* files that have been bundled with an application as assets -- that is,
|
* files that have been bundled with an application as assets -- that is,
|
||||||
* files placed in to the "assets" directory.
|
* files placed in to the "assets" directory.
|
||||||
*
|
*
|
||||||
* @param fileName The name of the asset to open. This name can be
|
* @param fileName The name of the asset to open. This name can be
|
||||||
* hierarchical.
|
* hierarchical.
|
||||||
*
|
*
|
||||||
* @see #open(String, int)
|
* @see #open(String, int)
|
||||||
* @see #list
|
* @see #list
|
||||||
*/
|
*/
|
||||||
@@ -353,11 +353,11 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* read its contents. This provides access to files that have been bundled
|
* read its contents. This provides access to files that have been bundled
|
||||||
* with an application as assets -- that is, files placed in to the
|
* with an application as assets -- that is, files placed in to the
|
||||||
* "assets" directory.
|
* "assets" directory.
|
||||||
*
|
*
|
||||||
* @param fileName The name of the asset to open. This name can be
|
* @param fileName The name of the asset to open. This name can be
|
||||||
* hierarchical.
|
* hierarchical.
|
||||||
* @param accessMode Desired access mode for retrieving the data.
|
* @param accessMode Desired access mode for retrieving the data.
|
||||||
*
|
*
|
||||||
* @see #ACCESS_UNKNOWN
|
* @see #ACCESS_UNKNOWN
|
||||||
* @see #ACCESS_STREAMING
|
* @see #ACCESS_STREAMING
|
||||||
* @see #ACCESS_RANDOM
|
* @see #ACCESS_RANDOM
|
||||||
@@ -397,14 +397,14 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a String array of all the assets at the given path.
|
* Return a String array of all the assets at the given path.
|
||||||
*
|
*
|
||||||
* @param path A relative path within the assets, i.e., "docs/home.html".
|
* @param path A relative path within the assets, i.e., "docs/home.html".
|
||||||
*
|
*
|
||||||
* @return String[] Array of strings, one for each asset. These file
|
* @return String[] Array of strings, one for each asset. These file
|
||||||
* names are relative to 'path'. You can open the file by
|
* names are relative to 'path'. You can open the file by
|
||||||
* concatenating 'path' and a name in the returned string (via
|
* concatenating 'path' and a name in the returned string (via
|
||||||
* File) and passing that to open().
|
* File) and passing that to open().
|
||||||
*
|
*
|
||||||
* @see #open
|
* @see #open
|
||||||
*/
|
*/
|
||||||
public native final String[] list(String path)
|
public native final String[] list(String path)
|
||||||
@@ -416,7 +416,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* provides direct access to all of the files included in an application
|
* provides direct access to all of the files included in an application
|
||||||
* package (not only its assets). Applications should not normally use
|
* package (not only its assets). Applications should not normally use
|
||||||
* this.
|
* this.
|
||||||
*
|
*
|
||||||
* @see #open(String)
|
* @see #open(String)
|
||||||
*/
|
*/
|
||||||
public final InputStream openNonAsset(String fileName) throws IOException {
|
public final InputStream openNonAsset(String fileName) throws IOException {
|
||||||
@@ -429,7 +429,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* provides direct access to all of the files included in an application
|
* provides direct access to all of the files included in an application
|
||||||
* package (not only its assets). Applications should not normally use
|
* package (not only its assets). Applications should not normally use
|
||||||
* this.
|
* this.
|
||||||
*
|
*
|
||||||
* @see #open(String, int)
|
* @see #open(String, int)
|
||||||
*/
|
*/
|
||||||
public final InputStream openNonAsset(String fileName, int accessMode)
|
public final InputStream openNonAsset(String fileName, int accessMode)
|
||||||
@@ -440,7 +440,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
* Open a non-asset in a specified package. Not for use by applications.
|
* Open a non-asset in a specified package. Not for use by applications.
|
||||||
*
|
*
|
||||||
* @param cookie Identifier of the package to be opened.
|
* @param cookie Identifier of the package to be opened.
|
||||||
* @param fileName Name of the asset to retrieve.
|
* @param fileName Name of the asset to retrieve.
|
||||||
*/
|
*/
|
||||||
@@ -452,7 +452,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
* Open a non-asset in a specified package. Not for use by applications.
|
* Open a non-asset in a specified package. Not for use by applications.
|
||||||
*
|
*
|
||||||
* @param cookie Identifier of the package to be opened.
|
* @param cookie Identifier of the package to be opened.
|
||||||
* @param fileName Name of the asset to retrieve.
|
* @param fileName Name of the asset to retrieve.
|
||||||
* @param accessMode Desired access mode for retrieving the data.
|
* @param accessMode Desired access mode for retrieving the data.
|
||||||
@@ -477,7 +477,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
return openNonAssetFd(0, fileName);
|
return openNonAssetFd(0, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final AssetFileDescriptor openNonAssetFd(int cookie,
|
public final AssetFileDescriptor openNonAssetFd(int cookie,
|
||||||
String fileName) throws IOException {
|
String fileName) throws IOException {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
@@ -492,20 +492,20 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
throw new FileNotFoundException("Asset absolute file: " + fileName);
|
throw new FileNotFoundException("Asset absolute file: " + fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a parser for a compiled XML file.
|
* Retrieve a parser for a compiled XML file.
|
||||||
*
|
*
|
||||||
* @param fileName The name of the file to retrieve.
|
* @param fileName The name of the file to retrieve.
|
||||||
*/
|
*/
|
||||||
public final XmlResourceParser openXmlResourceParser(String fileName)
|
public final XmlResourceParser openXmlResourceParser(String fileName)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
return openXmlResourceParser(0, fileName);
|
return openXmlResourceParser(0, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a parser for a compiled XML file.
|
* Retrieve a parser for a compiled XML file.
|
||||||
*
|
*
|
||||||
* @param cookie Identifier of the package to be opened.
|
* @param cookie Identifier of the package to be opened.
|
||||||
* @param fileName The name of the file to retrieve.
|
* @param fileName The name of the file to retrieve.
|
||||||
*/
|
*/
|
||||||
@@ -521,7 +521,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
* Retrieve a non-asset as a compiled XML file. Not for use by
|
* Retrieve a non-asset as a compiled XML file. Not for use by
|
||||||
* applications.
|
* applications.
|
||||||
*
|
*
|
||||||
* @param fileName The name of the file to retrieve.
|
* @param fileName The name of the file to retrieve.
|
||||||
*/
|
*/
|
||||||
/*package*/ final XmlBlock openXmlBlockAsset(String fileName)
|
/*package*/ final XmlBlock openXmlBlockAsset(String fileName)
|
||||||
@@ -533,7 +533,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
* Retrieve a non-asset as a compiled XML file. Not for use by
|
* Retrieve a non-asset as a compiled XML file. Not for use by
|
||||||
* applications.
|
* applications.
|
||||||
*
|
*
|
||||||
* @param cookie Identifier of the package to be opened.
|
* @param cookie Identifier of the package to be opened.
|
||||||
* @param fileName Name of the asset to retrieve.
|
* @param fileName Name of the asset to retrieve.
|
||||||
*/
|
*/
|
||||||
@@ -588,12 +588,18 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
destroy();
|
|
||||||
|
synchronized (this) {
|
||||||
|
if (mObject != 0) {
|
||||||
|
destroy();
|
||||||
|
mObject = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class AssetInputStream extends InputStream {
|
public final class AssetInputStream extends InputStream {
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
@@ -796,7 +802,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
/*package*/ native final String getResourcePackageName(int resid);
|
/*package*/ native final String getResourcePackageName(int resid);
|
||||||
/*package*/ native final String getResourceTypeName(int resid);
|
/*package*/ native final String getResourceTypeName(int resid);
|
||||||
/*package*/ native final String getResourceEntryName(int resid);
|
/*package*/ native final String getResourceEntryName(int resid);
|
||||||
|
|
||||||
private native final long openAsset(String fileName, int accessMode);
|
private native final long openAsset(String fileName, int accessMode);
|
||||||
private final native ParcelFileDescriptor openAssetFd(String fileName,
|
private final native ParcelFileDescriptor openAssetFd(String fileName,
|
||||||
long[] outOffsets) throws IOException;
|
long[] outOffsets) throws IOException;
|
||||||
@@ -856,17 +862,17 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public native static final int getGlobalAssetCount();
|
public native static final int getGlobalAssetCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public native static final String getAssetAllocations();
|
public native static final String getAssetAllocations();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
public native static final int getGlobalAssetManagerCount();
|
public native static final int getGlobalAssetManagerCount();
|
||||||
|
|
||||||
private native final long newTheme();
|
private native final long newTheme();
|
||||||
private native final void deleteTheme(long theme);
|
private native final void deleteTheme(long theme);
|
||||||
/*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
|
/*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
|
||||||
@@ -899,7 +905,7 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
mNumRefs++;
|
mNumRefs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final void decRefsLocked(long id) {
|
private final void decRefsLocked(long id) {
|
||||||
if (DEBUG_REFS && mRefStacks != null) {
|
if (DEBUG_REFS && mRefStacks != null) {
|
||||||
mRefStacks.remove(id);
|
mRefStacks.remove(id);
|
||||||
@@ -907,8 +913,9 @@ public final class AssetManager implements AutoCloseable {
|
|||||||
mNumRefs--;
|
mNumRefs--;
|
||||||
//System.out.println("Dec streams: mNumRefs=" + mNumRefs
|
//System.out.println("Dec streams: mNumRefs=" + mNumRefs
|
||||||
// + " mReleased=" + mReleased);
|
// + " mReleased=" + mReleased);
|
||||||
if (mNumRefs == 0) {
|
if (mNumRefs == 0 && mObject != 0) {
|
||||||
destroy();
|
destroy();
|
||||||
|
mObject = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user