Gating OutOfBoundsException on targetSdkVersion.
Apps targeting Pie or older will get the old undefined behavior. Apps
targeting Q or newer will get the OutOfBoundsException.
Bug: 118339123
Test: atest CtsUtilTestCases
Change-Id: Ibf5467aadec4a2f76ee180e963afeaf5a8a013a2
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9cd42a5..8f2ac0c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -137,6 +137,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SuperNotCalledException;
+import android.util.UtilConfig;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
import android.view.ContextThemeWrapper;
@@ -5978,6 +5979,10 @@
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
+ // Let the util.*Array classes maintain "undefined" for apps targeting Pie or earlier.
+ UtilConfig.setThrowExceptionForUpperArrayOutOfBounds(
+ data.appInfo.targetSdkVersion >= Build.VERSION_CODES.Q);
+
Message.updateCheckRecycle(data.appInfo.targetSdkVersion);
// Prior to P, internal calls to decode Bitmaps used BitmapFactory,
diff --git a/core/java/android/util/ArrayMap.java b/core/java/android/util/ArrayMap.java
index e2af6f5..7653c77 100644
--- a/core/java/android/util/ArrayMap.java
+++ b/core/java/android/util/ArrayMap.java
@@ -449,11 +449,17 @@
/**
* Return the key at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the key stored at the given index.
*/
public K keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -462,11 +468,17 @@
/**
* Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value stored at the given index.
*/
public V valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -475,12 +487,18 @@
/**
* Set the value at a given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @param value The new value to store at this index.
* @return Returns the previous value at the given index.
*/
public V setValueAt(int index, V value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -673,11 +691,17 @@
/**
* Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value that was stored at this index.
*/
public V removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java
index 4bd43d0..610641d 100644
--- a/core/java/android/util/ArraySet.java
+++ b/core/java/android/util/ArraySet.java
@@ -356,11 +356,17 @@
/**
* Return the value at the given index in the array.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value stored at the given index.
*/
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -527,11 +533,17 @@
/**
* Remove the key/value mapping at the given index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
+ *
* @param index The desired index, must be between 0 and {@link #size()}-1.
* @return Returns the value that was stored at this index.
*/
public E removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index e4de704..698b5b0 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -142,9 +142,14 @@
/**
* Removes the mapping at the specified index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -235,9 +240,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -258,10 +268,15 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -276,9 +291,14 @@
* Given an index in the range <code>0...size()-1</code>, sets a new
* value for the <code>index</code>th key-value mapping that this
* LongSparseArray stores.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, E value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index f167f00..b7c3e18 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -170,9 +170,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -189,9 +194,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 67dfb02..7a8c780 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -169,10 +169,12 @@
* Removes the mapping at the specified index.
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void removeAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -281,10 +283,12 @@
* key.</p>
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -307,11 +311,13 @@
* associated with the largest key.</p>
*
* <p>For indices outside of the range <code>0...size()-1</code>,
- * the behavior is undefined.</p>
+ * the behavior is undefined for apps targeting {@link android.os.Build.VERSION_CODES#P} and
+ * earlier, and an {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -327,10 +333,13 @@
* value for the <code>index</code>th key-value mapping that this
* SparseArray stores.
*
- * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined.</p>
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, E value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseBooleanArray.java b/core/java/android/util/SparseBooleanArray.java
index 03fa1c9..5574047 100644
--- a/core/java/android/util/SparseBooleanArray.java
+++ b/core/java/android/util/SparseBooleanArray.java
@@ -166,9 +166,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -185,9 +190,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public boolean valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -196,9 +206,14 @@
/**
* Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, boolean value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index c68dc4e..84f9269 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -170,9 +170,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -189,9 +194,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -200,9 +210,14 @@
/**
* Directly set the value at a particular index.
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public void setValueAt(int index, int value) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/SparseLongArray.java b/core/java/android/util/SparseLongArray.java
index 37a9202..00e39a9 100644
--- a/core/java/android/util/SparseLongArray.java
+++ b/core/java/android/util/SparseLongArray.java
@@ -180,9 +180,14 @@
* be in ascending order, e.g., <code>keyAt(0)</code> will return the
* smallest key and <code>keyAt(size()-1)</code> will return the largest
* key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public int keyAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
@@ -199,9 +204,14 @@
* <code>valueAt(0)</code> will return the value associated with the
* smallest key and <code>valueAt(size()-1)</code> will return the value
* associated with the largest key.</p>
+ *
+ * <p>For indices outside of the range <code>0...size()-1</code>, the behavior is undefined for
+ * apps targeting {@link android.os.Build.VERSION_CODES#P} and earlier, and an
+ * {@link ArrayIndexOutOfBoundsException} is thrown for apps targeting
+ * {@link android.os.Build.VERSION_CODES#Q} and later.</p>
*/
public long valueAt(int index) {
- if (index >= mSize) {
+ if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
// The array might be slightly bigger than mSize, in which case, indexing won't fail.
throw new ArrayIndexOutOfBoundsException(index);
}
diff --git a/core/java/android/util/UtilConfig.java b/core/java/android/util/UtilConfig.java
new file mode 100644
index 0000000..7658c40
--- /dev/null
+++ b/core/java/android/util/UtilConfig.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * Class to configure several of the util classes.
+ *
+ * @hide
+ */
+public class UtilConfig {
+ static boolean sThrowExceptionForUpperArrayOutOfBounds = true;
+
+ public static void setThrowExceptionForUpperArrayOutOfBounds(boolean check) {
+ sThrowExceptionForUpperArrayOutOfBounds = check;
+ }
+}