diff options
author | Alan Viverette <alanv@google.com> | 2014-03-27 15:39:15 -0700 |
---|---|---|
committer | Alan Viverette <alanv@google.com> | 2014-03-27 15:39:15 -0700 |
commit | fd274a0d4ab5a6777213fecb8ddf6e8099675283 (patch) | |
tree | 9965761c44b72261485a384cef6fe58f0b70bfae | |
parent | 9ad8a5331ca5eb6390c702ec57952043b56170bf (diff) | |
download | frameworks_base-fd274a0d4ab5a6777213fecb8ddf6e8099675283.zip frameworks_base-fd274a0d4ab5a6777213fecb8ddf6e8099675283.tar.gz frameworks_base-fd274a0d4ab5a6777213fecb8ddf6e8099675283.tar.bz2 |
Enforce restrictions on recycled TypedArrays
No calls may be made to recycled TypedArrays, and we'll throw a
detailed exception if developers attempt to do so. Also fixes the
place where we were doin' it wrong.
BUG: 13673783
Change-Id: Ia7a382d90fce8aef7741d926028b2d01b57435ae
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 3 | ||||
-rw-r--r-- | core/java/android/content/res/TypedArray.java | 316 |
2 files changed, 214 insertions, 105 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index cf44ad8..ab0a589 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -1010,13 +1010,14 @@ public class PackageParser { pkg.mSharedUserLabel = sa.getResourceId( com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0); } - sa.recycle(); pkg.installLocation = sa.getInteger( com.android.internal.R.styleable.AndroidManifest_installLocation, PARSE_DEFAULT_INSTALL_LOCATION); pkg.applicationInfo.installLocation = pkg.installLocation; + sa.recycle(); + /* Set the global "forward lock" flag */ if ((flags & PARSE_FORWARD_LOCK) != 0) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 9fb2846..15337ce 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -32,7 +32,7 @@ import java.util.Arrays; * {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)} * or {@link Resources#obtainAttributes}. Be * sure to call {@link #recycle} when done with them. - * + * * The indices used to retrieve values from this structure correspond to * the positions of the attributes given to obtainStyledAttributes. */ @@ -46,6 +46,7 @@ public class TypedArray { attrs.mResources = res; attrs.mMetrics = res.getDisplayMetrics(); attrs.mAssets = res.getAssets(); + attrs.mRecycled = false; final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES; if (attrs.mData.length >= fullLen) { @@ -65,6 +66,8 @@ public class TypedArray { private Resources mResources; private DisplayMetrics mMetrics; private AssetManager mAssets; + private boolean mRecycled; + /*package*/ XmlBlock.Parser mXml; /*package*/ Resources.Theme mTheme; /*package*/ int[] mData; @@ -76,45 +79,65 @@ public class TypedArray { * Return the number of values in this array. */ public int length() { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + return mLength; } - + /** * Return the number of indices in the array that actually have data. */ public int getIndexCount() { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + return mIndices[0]; } - + /** * Return an index in the array that has data. - * + * * @param at The index you would like to returned, ranging from 0 to * {@link #getIndexCount()}. - * + * * @return The index at the given offset, which can be used with * {@link #getValue} and related APIs. */ public int getIndex(int at) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + return mIndices[1+at]; } - + /** * Return the Resources object this array was loaded from. */ public Resources getResources() { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + return mResources; } - + /** * Retrieve the styled string value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. - * - * @return CharSequence holding string data. May be styled. Returns + * + * @return CharSequence holding string data. May be styled. Returns * null if the attribute is not defined. */ public CharSequence getText(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -136,13 +159,17 @@ public class TypedArray { /** * Retrieve the string value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. - * + * * @return String holding string data. Any styling information is * removed. Returns null if the attribute is not defined. */ public String getString(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -170,14 +197,18 @@ public class TypedArray { * attributes, or conversions from other types. As such, this method * will only return strings for TypedArray objects that come from * attributes in an XML file. - * + * * @param index Index of attribute to retrieve. - * + * * @return String holding string data. Any styling information is * removed. Returns null if the attribute is not defined or is not * an immediate string value. */ public String getNonResourceString(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -190,12 +221,12 @@ public class TypedArray { } return null; } - + /** * @hide * Retrieve the string value for the attribute at <var>index</var> that is * not allowed to change with the given configurations. - * + * * @param index Index of attribute to retrieve. * @param allowedChangingConfigs Bit mask of configurations from * {@link Configuration}.NATIVE_CONFIG_* that are allowed to change. @@ -204,6 +235,10 @@ public class TypedArray { * removed. Returns null if the attribute is not defined. */ public String getNonConfigurationString(int index, int allowedChangingConfigs) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -229,13 +264,17 @@ public class TypedArray { /** * Retrieve the boolean value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined. - * + * * @return Attribute boolean value, or defValue if not defined. */ public boolean getBoolean(int index, boolean defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -259,13 +298,17 @@ public class TypedArray { /** * Retrieve the integer value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined. - * + * * @return Attribute int value, or defValue if not defined. */ public int getInt(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -289,12 +332,16 @@ public class TypedArray { /** * Retrieve the float value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. - * + * * @return Attribute float value, or defValue if not defined.. */ public float getFloat(int index, float defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -319,20 +366,24 @@ public class TypedArray { + Integer.toHexString(type)); return defValue; } - + /** * Retrieve the color value for the attribute at <var>index</var>. If * the attribute references a color resource holding a complex * {@link android.content.res.ColorStateList}, then the default color from * the set is returned. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute color value, or defValue if not defined. */ public int getColor(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -359,12 +410,16 @@ public class TypedArray { * Retrieve the ColorStateList for the attribute at <var>index</var>. * The value may be either a single solid color or a reference to * a color or complex {@link android.content.res.ColorStateList} description. - * + * * @param index Index of attribute to retrieve. - * + * * @return ColorStateList for the attribute, or null if not defined. */ public ColorStateList getColorStateList(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + final TypedValue value = mValue; if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { return mResources.loadColorStateList(value, value.resourceId); @@ -374,14 +429,18 @@ public class TypedArray { /** * Retrieve the integer value for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute integer value, or defValue if not defined. */ public int getInteger(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -397,22 +456,26 @@ public class TypedArray { } /** - * Retrieve a dimensional unit attribute at <var>index</var>. Unit - * conversions are based on the current {@link DisplayMetrics} - * associated with the resources this {@link TypedArray} object - * came from. - * + * Retrieve a dimensional unit attribute at <var>index</var>. Unit + * conversions are based on the current {@link DisplayMetrics} + * associated with the resources this {@link TypedArray} object + * came from. + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric, or defValue if not defined. - * + * * @see #getDimensionPixelOffset * @see #getDimensionPixelSize */ public float getDimension(int index, float defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -433,18 +496,22 @@ public class TypedArray { * {@link #getDimension}, except the returned value is converted to * integer pixels for you. An offset conversion involves simply * truncating the base value to an integer. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. - * + * * @see #getDimension * @see #getDimensionPixelSize */ public int getDimensionPixelOffset(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -466,18 +533,22 @@ public class TypedArray { * integer pixels for use as a size. A size conversion involves * rounding the base value, and ensuring that a non-zero base value * is at least one pixel in size. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. - * + * * @see #getDimension * @see #getDimensionPixelOffset */ public int getDimensionPixelSize(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -497,14 +568,18 @@ public class TypedArray { * {@link android.view.ViewGroup}'s layout_width and layout_height * attributes. This is only here for performance reasons; applications * should use {@link #getDimensionPixelSize}. - * + * * @param index Index of the attribute to retrieve. * @param name Textual name of attribute for error reporting. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels. */ public int getLayoutDimension(int index, String name) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -519,21 +594,25 @@ public class TypedArray { throw new RuntimeException(getPositionDescription() + ": You must supply a " + name + " attribute."); } - + /** * Special version of {@link #getDimensionPixelSize} for retrieving * {@link android.view.ViewGroup}'s layout_width and layout_height * attributes. This is only here for performance reasons; applications * should use {@link #getDimensionPixelSize}. - * + * * @param index Index of the attribute to retrieve. * @param defValue The default value to return if this attribute is not * default or contains the wrong type of data. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels. */ public int getLayoutDimension(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -550,20 +629,24 @@ public class TypedArray { /** * Retrieve a fractional unit attribute at <var>index</var>. - * - * @param index Index of attribute to retrieve. - * @param base The base value of this fraction. In other words, a + * + * @param index Index of attribute to retrieve. + * @param base The base value of this fraction. In other words, a * standard fraction is multiplied by this value. - * @param pbase The parent base value of this fraction. In other + * @param pbase The parent base value of this fraction. In other * words, a parent fraction (nn%p) is multiplied by this * value. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute fractional value multiplied by the appropriate - * base value, or defValue if not defined. + * + * @return Attribute fractional value multiplied by the appropriate + * base value, or defValue if not defined. */ public float getFraction(int index, int base, int pbase, float defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; @@ -580,19 +663,23 @@ public class TypedArray { /** * Retrieve the resource identifier for the attribute at - * <var>index</var>. Note that attribute resource as resolved when - * the overall {@link TypedArray} object is retrieved. As a - * result, this function will return the resource identifier of the - * final resource value that was found, <em>not</em> necessarily the - * original resource that was specified by the attribute. - * + * <var>index</var>. Note that attribute resource as resolved when + * the overall {@link TypedArray} object is retrieved. As a + * result, this function will return the resource identifier of the + * final resource value that was found, <em>not</em> necessarily the + * original resource that was specified by the attribute. + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute resource identifier, or defValue if not defined. */ public int getResourceId(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) { @@ -615,6 +702,10 @@ public class TypedArray { * @hide */ public int getThemeAttributeId(int index, int defValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) { @@ -628,12 +719,16 @@ public class TypedArray { * gets the resource ID of the selected attribute, and uses * {@link Resources#getDrawable Resources.getDrawable} of the owning * Resources object to retrieve its Drawable. - * + * * @param index Index of attribute to retrieve. - * + * * @return Drawable for the attribute, or null if not defined. */ public Drawable getDrawable(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + final TypedValue value = mValue; if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { if (false) { @@ -655,12 +750,16 @@ public class TypedArray { * This gets the resource ID of the selected attribute, and uses * {@link Resources#getTextArray Resources.getTextArray} of the owning * Resources object to retrieve its String[]. - * + * * @param index Index of attribute to retrieve. - * + * * @return CharSequence[] for the attribute, or null if not defined. */ public CharSequence[] getTextArray(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + final TypedValue value = mValue; if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { if (false) { @@ -679,36 +778,19 @@ public class TypedArray { /** * Retrieve the raw TypedValue for the attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. * @param outValue TypedValue object in which to place the attribute's * data. - * - * @return Returns true if the value was retrieved, else false. - */ - public boolean getValue(int index, TypedValue outValue) { - return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue); - } - - /** - * Determines whether this TypedArray contains an attribute of the specified - * type. * - * @param type Type of data, e.g. {@link TypedValue#TYPE_ATTRIBUTE} - * @return True if the TypedArray contains an attribute of the specified - * type. - * @hide + * @return Returns true if the value was retrieved, else false. */ - public boolean hasType(int type) { - final int[] data = mData; - final int N = getIndexCount(); - for (int i = 0; i < N; i++) { - final int index = getIndex(i) * AssetManager.STYLE_NUM_ENTRIES; - if (data[index + AssetManager.STYLE_TYPE] == type) { - return true; - } + public boolean getValue(int index, TypedValue outValue) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); } - return false; + + return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue); } /** @@ -718,36 +800,48 @@ public class TypedArray { * @return Attribute type. */ public int getType(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; return mData[index + AssetManager.STYLE_TYPE]; } /** * Determines whether there is an attribute at <var>index</var>. - * + * * @param index Index of attribute to retrieve. - * + * * @return True if the attribute has a value, false otherwise. */ public boolean hasValue(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; final int type = data[index+AssetManager.STYLE_TYPE]; return type != TypedValue.TYPE_NULL; } - + /** - * Retrieve the raw TypedValue for the attribute at <var>index</var> - * and return a temporary object holding its data. This object is only - * valid until the next call on to {@link TypedArray}. - * + * Retrieve the raw TypedValue for the attribute at <var>index</var> + * and return a temporary object holding its data. This object is only + * valid until the next call on to {@link TypedArray}. + * * @param index Index of attribute to retrieve. - * - * @return Returns a TypedValue object if the attribute is defined, + * + * @return Returns a TypedValue object if the attribute is defined, * containing its data; otherwise returns null. (You will not * receive a TypedValue whose type is TYPE_NULL.) */ public TypedValue peekValue(int index) { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + final TypedValue value = mValue; if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) { return value; @@ -759,13 +853,23 @@ public class TypedArray { * Returns a message about the parser state suitable for printing error messages. */ public String getPositionDescription() { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + return mXml != null ? mXml.getPositionDescription() : "<internal>"; } /** - * Give back a previously retrieved array, for later re-use. + * Recycle the TypedArray, to be re-used by a later caller. After calling + * this function you must not ever touch the typed array again. */ public void recycle() { + if (mRecycled) { + throw new RuntimeException(toString() + " recycled twice!"); + } + + mRecycled = true; mResources = null; mMetrics = null; mAssets = null; @@ -791,6 +895,10 @@ public class TypedArray { * @hide */ public int[] extractThemeAttrs() { + if (mRecycled) { + throw new RuntimeException("Cannot make calls to a recycled instance!"); + } + int[] attrs = null; final int N = length(); |