Preventing recursive referrence in drawables
am: 99b25d2817
Change-Id: I1c23d40e590d6d8bb21f6734a106d0ee217b6672
This commit is contained in:
@@ -49,6 +49,8 @@ import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.DisplayAdjustments;
|
||||
|
||||
import com.android.internal.util.GrowingArrayUtils;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@@ -117,6 +119,13 @@ public class ResourcesImpl {
|
||||
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
|
||||
new ConfigurationBoundResourceCache<>();
|
||||
|
||||
// A stack of all the resourceIds already referenced when parsing a resource. This is used to
|
||||
// detect circular references in the xml.
|
||||
// Using a ThreadLocal variable ensures that we have different stacks for multiple parallel
|
||||
// calls to ResourcesImpl
|
||||
private final ThreadLocal<LookupStack> mLookupStack =
|
||||
ThreadLocal.withInitial(() -> new LookupStack());
|
||||
|
||||
/** Size of the cyclical cache used to map XML files to blocks. */
|
||||
private static final int XML_BLOCK_CACHE_SIZE = 4;
|
||||
|
||||
@@ -784,19 +793,29 @@ public class ResourcesImpl {
|
||||
final Drawable dr;
|
||||
|
||||
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
|
||||
LookupStack stack = mLookupStack.get();
|
||||
try {
|
||||
if (file.endsWith(".xml")) {
|
||||
final XmlResourceParser rp = loadXmlResourceParser(
|
||||
file, id, value.assetCookie, "drawable");
|
||||
dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
|
||||
rp.close();
|
||||
} else {
|
||||
final InputStream is = mAssets.openNonAsset(
|
||||
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
|
||||
dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
|
||||
is.close();
|
||||
// Perform a linear search to check if we have already referenced this resource before.
|
||||
if (stack.contains(id)) {
|
||||
throw new Exception("Recursive reference in drawable");
|
||||
}
|
||||
} catch (Exception | StackOverflowError e) {
|
||||
stack.push(id);
|
||||
try {
|
||||
if (file.endsWith(".xml")) {
|
||||
final XmlResourceParser rp = loadXmlResourceParser(
|
||||
file, id, value.assetCookie, "drawable");
|
||||
dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
|
||||
rp.close();
|
||||
} else {
|
||||
final InputStream is = mAssets.openNonAsset(
|
||||
value.assetCookie, file, AssetManager.ACCESS_STREAMING);
|
||||
dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
|
||||
is.close();
|
||||
}
|
||||
} finally {
|
||||
stack.pop();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
|
||||
final NotFoundException rnf = new NotFoundException(
|
||||
"File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
|
||||
@@ -1377,4 +1396,29 @@ public class ResourcesImpl {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LookupStack {
|
||||
|
||||
// Pick a reasonable default size for the array, it is grown as needed.
|
||||
private int[] mIds = new int[4];
|
||||
private int mSize = 0;
|
||||
|
||||
public void push(int id) {
|
||||
mIds = GrowingArrayUtils.append(mIds, mSize, id);
|
||||
mSize++;
|
||||
}
|
||||
|
||||
public boolean contains(int id) {
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
if (mIds[i] == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void pop() {
|
||||
mSize--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user