在我的测试中,我在ActivityManagerService的updateOomAdjLocked()中看到以下异常:
// java.lang.IndexOutOfBoundsException: Invalid index 27, size is 27
// at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
// at java.util.ArrayList.get(ArrayList.java:304)
// at com.android.server.am.ActivityManagerService.updateOomAdjLocked(ActivityManagerService.java:13880)
// at com.android.server.am.ActivityManagerService.updateLruProcessLocked(ActivityManagerService.java:1904)
// at com.android.server.am.ActivityStack.realStartActivityLocked(ActivityStack.java:647)
// at com.android.server.am.ActivityStack.startSpecificActivityLocked(ActivityStack.java:803)
以下是有问题的代码(适用于Android 4.2.2 r1.2的13850行):
final ArrayList<ProcessRecord> mLruProcesses
= new ArrayList<ProcessRecord>();
{...}
final void updateOomAdjLocked() {
{...}
final int N = mLruProcesses.size();
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
{...}
}
如果在循环中调用了mLruProcesses.remove,则i = N的mLruProcesses.get(i)将访问不存在的索引,从而触发异常。
到目前为止,我对Android服务知之甚少,所以我的问题是,是否需要重新输入此代码,也许是通过使某些操作成为线程安全的?
最佳答案
您可以验证循环中mLruProcess.size()
的大小是否仍等于N
。
final boolean updateOomAdjLocked() {
{...}
final int N = mLruProcess.size();
for(int i = 0; i < N; i++) {
if(N != mLruProcess.size()) {
//Do something accordingly, in this case return false
return false;
}
ProcessRecord app = mLruProcess.get(i);
{...}
}
{...}
return true;
}
在调用此函数的地方添加一些逻辑,如果它返回false,请尝试再次调用该函数。否则,可以将
mLruProcess
放在Synchronized
块中,这意味着只能在一个并发线程中对其进行访问。 Synchronized
关键字正在阻止,这意味着试图访问另一个线程中的mLruProcess
的任何代码都将被阻止,直到使用mLruProcess完成当前线程为止。如果您不喜欢或不能使用阻止代码,请尝试使用
AtomicBoolean
,如下所示:When to use synchronized in Java
每当更改
AtomicBoolean
中存储的对象时,都设置mLruProcess
,然后在需要访问AtomicBoolean
中存储的对象的所有位置检查mLruProcess
。