在我的测试中,我在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

07-26 04:01