1

在我的测试中,我在 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,则 mLruProcesses.get(i) for i=N 访问不存在的索引,从而触发异常。

到目前为止,我对 Android 服务知之甚少,所以我的问题是这段代码是否需要可重新输入,也许是通过使某些操作线程安全?

4

1 回答 1

2

您可以验证循环中的大小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如下所示的:

何时在 Java 中使用同步

AtomicBoolean每当您更改存储在中的对象时设置mLruProcess,然后检查AtomicBoolean您需要访问存储在中的对象的任何地方mLruProcess

于 2013-07-09T18:25:55.643 回答