Android 调用SparseArray的put方法报数组越界.

突然报SystemUI crash,查看log是数组越界:

04-23 05:23:58.484 2838 3037 E AndroidRuntime: FATAL EXCEPTION: Recents-TaskResourceLoader
04-23 05:23:58.484 2838 3037 E AndroidRuntime: Process: com.android.systemui, PID: 2838
04-23 05:23:58.484 2838 3037 E AndroidRuntime: java.lang.ArrayIndexOutOfBoundsException: src.length=23 srcPos=-14 dst.length=23 dstPos=-13 length=36
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at java.lang.System.arraycopy(Native Method)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at com.android.internal.util.GrowingArrayUtils.insert(GrowingArrayUtils.java:150)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at android.util.SparseArray.put(SparseArray.java:246)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at com.android.systemui.shared.recents.model.TaskKeyCache.put(TaskKeyCache.java:67)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at com.android.systemui.shared.recents.model.IconLoader.getIcon(IconLoader.java:77)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at com.android.systemui.shared.recents.model.BackgroundTaskLoader.processLoadQueueItem(BackgroundTaskLoader.java:140)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at com.android.systemui.shared.recents.model.BackgroundTaskLoader.run(BackgroundTaskLoader.java:109)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:873)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:99)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at android.os.Looper.loop(Looper.java:210)
04-23 05:23:58.484 2838 3037 E AndroidRuntime: at android.os.HandlerThread.run(HandlerThread.java:65)

查看代码是SparseArray.java的put方法插入值的时候i取了小于0,但是看不懂是怎么负值的:

public void put(int key, E value) {
// 二分查找,key在mKeys列表中对应的index
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
// 如果找到,则直接赋值
if (i >= 0) {
mValues[i] = value;
}
// 找不到
else {
// binarySearch方法中,找不到时,i取了其非,这里再次取非,则非非则正
i = ~i;
// 如果该位置的数据正好被删除,则赋值
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
// 如果有数据被删除了,则gc
if (mGarbage && mSize >= mKeys.length) {
gc();
// Search again because indices may have changed.
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
// 插入数据,增长mKeys与mValues列表
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);//这里i取了-14导致异常,不知道怎么回事.
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}

看了下SparseArray是线程不安全的,怀疑是不是多线程调用的时候被其他线程插入了数据,但是不知道怎么去排查.

确实是由于多线程不安全造成的,在TaskKeyCache.java里调用的地方加锁,谷歌在Q上已经这样解决,低概率问题无法手动复现

https://blog.csdn.net/xyz_fly/article/details/7931943

首先SparseArray多线程调用肯定有问题,查查你的代码有没有多线程同时操作的地方
如果没有当然是一步步分析了
1.找到SparseArray使用的地方
2.对使用的地方进行debug或打log信息
剩下的就很好解决了,打印出SparseArray的状态、操作、数据应该有非法操作