遇到的问题:
12-30 18:43:57.442 +0800 16559 16559 E Zygote : java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@2eb3071rejected from java.util.concurrent.ThreadPoolExecutor@30dfbd5[Running, pool size = 17, active threads = 17, queued tasks = 128, completed tasks = 303920]
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2078)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:843)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1389)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:651)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at com.android.server.OpsService$1.run(SmtOpsService.java:100)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at android.os.Handler.handleCallback(Handler.java:790)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at android.os.Handler.dispatchMessage(Handler.java:99)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at android.os.Looper.loop(Looper.java:164)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at com.android.server.SystemServer.run(SystemServer.java:456)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at com.android.server.SystemServer.main(SystemServer.java:289)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at java.lang.reflect.Method.invoke(Native Method)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
12-30 18:43:57.442 +0800 16559 16559 E Zygote : at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:800)
AsyncTask.THREAD_POOL_EXECUTOR的queued task满了,pool size也超过了上限。原因是有一个第三方应用出现了异常,不停地死掉重启,导致在updateOom的时候反复设置其process group,把任务队列填满了,别的地方再向AsyncTask里面加任务时就崩了。
原来的代码:
void asyncSetProcessGroupAll (int uid, int pid, int processGroup) {
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
try {
Process.setProcessGroupAll(uid, pid, processGroup);
} catch (Exception e) {
Slog.w(TAG, "Failed setting process group of " + pid + " to " + processGroup, e);
}
}
});
}
修改的思路有两点,首先不用AsyncTask了,这东西毕竟是公共的,堵死了大家都受影响,自己单独搞一个线程池。
第二就是即使使用了自己的线程池,对这种有破坏性的应用也要进行约束。同时仅有一个线程为其服务。
修改后的代码:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT / 2;
private static final int KEEP_ALIVE_SECONDS = 15;
final ThreadPoolExecutor mThreadPoolExecutor =
new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
new LinkedBlockingQueue
private class PGInfo {
int uid;
int processGroup;
PGInfo(int uid, int processGroup) {
this.uid = uid;
this.processGroup = processGroup;
}
}
private HashMap
void asyncSetProcessGroupAll (int uid, int pid, int processGroup) {
synchronized (mPGMap) {
PGInfo info = mPGMap.get(pid);
if (null == info) {
info = new PGInfo(uid, processGroup);
mPGMap.put(pid, info);
} else {
info.uid = uid;
info.processGroup = processGroup;
return;
}
}
mThreadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
PGInfo info;
int tmpUid, tmpProcessGroup;
synchronized (mPGMap) {
info = mPGMap.get(pid);
tmpUid = info.uid;
tmpProcessGroup = info.processGroup;
}
while (true) {
try {
Process.setProcessGroupAll(tmpUid, pid, tmpProcessGroup);
} catch (Exception e) {
Slog.w(TAG, "Failed setting process group of " + pid + " to " + tmpProcessGroup, e);
} finally {
synchronized (mPGMap) {
if (tmpUid == info.uid && tmpProcessGroup == info.processGroup) {
mPGMap.remove(pid);
break;
} else {
tmpUid = info.uid;
tmpProcessGroup = info.processGroup;
}
}
}
}
}
});
}