最近遇到 进程被杀的情况,当然这只是Android杀进程的其中一种机制。顺便分析,学习一下。
log如下:
ActivityManager: Killing 19893:com.xxx.xxx/u0a106 (adj 500): excessive cpu 7180 during 300080 dur=42644246 limit=2
ActivityManager: Killing 22598:com.xxx.xxx/u0a106 (adj 500): excessive cpu 21890 during 300019 dur=45344791 limit=2
ActivityManager: Killing 31530:com.xxx.xxx/u0a106 (adj 500): excessive cpu 19230 during 300017 dur=31239455 limit=2
ActivityManager: Killing 22598:com.xxx.xxx/u0a106 (adj 500): excessive cpu 21890 during 300019 dur=45344791 limit=2
AMS 每 5分钟(基于 Android 8.1源码) 检查一下异常耗电情况:
final void checkExcessivePowerUsageLocked() {
updateCpuStatsNow();
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
boolean doCpuKills = true;
if (mLastPowerCheckUptime == 0) {
doCpuKills = false;
}
final long curUptime = SystemClock.uptimeMillis();//从开机到现在的毫秒数,不包括睡眠的时间
final long uptimeSince = curUptime - mLastPowerCheckUptime;//距上次检查的时间间隔
mLastPowerCheckUptime = curUptime;
int i = mLruProcesses.size();
while (i > 0) {
i--;
ProcessRecord app = mLruProcesses.get(i);
if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
if (app.lastCpuTime <= 0) {
continue;
}
long cputimeUsed = app.curCpuTime - app.lastCpuTime;//检查周期内进程CPU使用时长
if (DEBUG_POWER) {
StringBuilder sb = new StringBuilder(128);
sb.append("CPU for ");
app.toShortString(sb);
sb.append(": over ");
TimeUtils.formatDuration(uptimeSince, sb);
sb.append(" used ");
TimeUtils.formatDuration(cputimeUsed, sb);
sb.append(" (");
sb.append((cputimeUsed*100)/uptimeSince);
sb.append("%)");
Slog.i(TAG_POWER, sb.toString());
}
//随着应用退到后台的时间越来越长,进程被允许使用的CPU占比越来越小
// If the process has used too much CPU over the last duration, the
// user probably doesn't want this, so kill!
if (doCpuKills && uptimeSince > 0) {
// What is the limit for this process?
int cpuLimit;
long checkDur = curUptime - app.whenUnimportant;
if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;//25
} else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*2)
|| app.setProcState <= ActivityManager.PROCESS_STATE_HOME) {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2;//25
} else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL*3)) {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3;//10
} else {
cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;//2
}
if (((cputimeUsed*100)/uptimeSince) >= cpuLimit) {
synchronized (stats) {
stats.reportExcessiveCpuLocked(app.info.uid, app.processName,
uptimeSince, cputimeUsed);
}
app.kill("excessive cpu " + cputimeUsed + " during " + uptimeSince
+ " dur=" + checkDur + " limit=" + cpuLimit, true);
app.baseProcessTracker.reportExcessiveCpu(app.pkgList);
}
}
app.lastCpuTime = app.curCpuTime;
}
}
}
随着应用退到后台的时间越来越长,进程被允许使用的CPU占比越来越小:
退到后台时间 | 允许使用的最大CPU占比 |
---|---|
time <= 5min | 25% |
5min < time <= 10min | 25% |
10min < time <=15min | 10% |
>15min | 2% |
这个占比的计算方式是:
rate = cputimeUsed*100/uptimeSince 一个检查周期内CPU的使用时长 / 检查周期时长
从上面的log看 是在 Xxx进程退到后台15分钟以后,使用CPU占比超过 2% 触发的。
譬如说进程退到后台15分钟后,在某次检查中,发现5分钟内CPU处于活动状态的时间是 100s, 而该进程占用CPU的时长如果超过 2s (100s * 2% ), 就会触发 杀进程机制。