原生HighCPU机制

一:背景

出现查杀:

Line 11157: 08-13 11:17:02.407361  1697  1731 I am_kill : [0,18313,com.ss.android.ugc.aweme,900,excessive cpu 72610 during 60054 dur=107220 limit=75] //在60s的检查周期内,进程使用了72s(变成非重要进程的时间),超过了阈值75(时间越久值越大)

二:方案介绍

系统资源是有限的,后台应用如果长时间使用CPU,可能会影响前台应用,造成前台应用卡顿(抢占CPU资源)。轮询查看后台高负载的应用,发现其CPU占用高可通知进行查杀。

三:功能实现

1 ActivityManagerService.finishBooting

系统开机完成,ActivitymanagerService.finishBooting函数会被调用,在finishBooting(5分钟后)会发送CHECK_EXCESSIVE_POWER_USE_MSG message来开始监听之旅。在接收到该message消息时,会检查应用的CPU使用情况,并以5分钟的时间间隔来不断循环检查。

            Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
            mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);

            case CHECK_EXCESSIVE_POWER_USE_MSG: {
                checkExcessivePowerUsage();
                removeMessages(CHECK_EXCESSIVE_POWER_USE_MSG);
                Message nmsg = obtainMessage(CHECK_EXCESSIVE_POWER_USE_MSG);
                sendMessageDelayed(nmsg, mConstants.POWER_CHECK_INTERVAL);

  private static final long DEFAULT_POWER_CHECK_INTERVAL = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;

2 ActivityManagerService.checkExcessivePowerUsage

遍历LRU list所有进程,针对优先级低于PROCESS_STATE_HOME的进程,根据进程状态改变距离现在的时间,设置不同的限制阈值,然后调用updateAppProcessCpuTimeLPr继续检查流程。

    private void checkExcessivePowerUsage() {
        //更新CPU统计信息
        updateCpuStatsNow();
 
        ...
        synchronized (mProcLock) {
            //mLastPowerCheckUptime为上一次检查时间,第一次检查时,该值为0
            final boolean doCpuKills = mLastPowerCheckUptime != 0;
            final long curUptime = SystemClock.uptimeMillis();
            //从上次检查到现在的时间
            final long uptimeSince = curUptime - mLastPowerCheckUptime;
            //把当前时间赋值给mLastPowerCheckUptime
            mLastPowerCheckUptime = curUptime;
            //遍历LRU list中所有进程
            mProcessList.forEachLruProcessesLOSP(false, app -> {
                //如果是空进程,直接return
                if (app.getThread() == null) {
                    return;
                }
                //优先级低于PROCESS_STATE_HOME的进程
                if (app.mState.getSetProcState() >= ActivityManager.PROCESS_STATE_HOME) {
                    //检查阈值
                    int cpuLimit;
                    //进程开始变成非重要进程到现在的时间
                    long checkDur = curUptime - app.mState.getWhenUnimportant();
                    //根据进程状态改变的时间,设置不同的阈值
                    if (checkDur <= mConstants.POWER_CHECK_INTERVAL) {//5min
                        cpuLimit = mConstants.POWER_CHECK_MAX_CPU_1;//25
                    } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 2)
                            || app.mState.getSetProcState() <= ActivityManager.PROCESS_STATE_HOME) {//10min
                        cpuLimit = mConstants.POWER_CHECK_MAX_CPU_2;//25
                    } else if (checkDur <= (mConstants.POWER_CHECK_INTERVAL * 3)) {//15min
                        cpuLimit = mConstants.POWER_CHECK_MAX_CPU_3;//10
                    } else {
                        cpuLimit = mConstants.POWER_CHECK_MAX_CPU_4;//2
                    }
 
                    //继续检查流程
                    updateAppProcessCpuTimeLPr(uptimeSince, doCpuKills, checkDur, cpuLimit, app);
                    ...
                }
            });
        }
    }

3 ActivityManagerService.updateAppProcessCpuTimeLPr

通过ProcessProfileRecord,计算出进程已经使用CPU的时间,调用checkExcessivePowerUsageLPr函数来检查是否超过限制阈值,如果超过则杀进程

    private void updateAppProcessCpuTimeLPr(final long uptimeSince, final boolean doCpuKills,
            final long checkDur, final int cpuLimit, final ProcessRecord app) {
        synchronized (mAppProfiler.mProfilerLock) {
            final ProcessProfileRecord profile = app.mProfile;
            //通过ProcessProfileRecord获取当前CPU使用时间
            final long curCpuTime = profile.mCurCpuTime.get();
            //通过ProcessProfileRecord获取上次CPU使用时间
            final long lastCpuTime = profile.mLastCpuTime.get();
            if (lastCpuTime > 0) {
                //该进程已经使用CPU的时间
                final long cpuTimeUsed = curCpuTime - lastCpuTime;
                //检查进程CPU使用时间是否超过阈值
                if (checkExcessivePowerUsageLPr(uptimeSince, doCpuKills, cpuTimeUsed,
                            app.processName, app.toShortString(), cpuLimit, app)) {
                    mHandler.post(() -> {
                        synchronized (ActivityManagerService.this) {
                            //如果是空进程或者优先级高于PROCESS_STATE_HOME的进程
                            if (app.getThread() == null
                               || app.mState.getSetProcState() < ActivityManager.PROCESS_STATE_HOME) {
                                   return;
                            }
                            //杀进程
                            app.killLocked("excessive cpu " + cpuTimeUsed + " during "
                                    + uptimeSince + " dur=" + checkDur + " limit=" + cpuLimit,
                                    ApplicationExitInfo.REASON_EXCESSIVE_RESOURCE_USAGE,
                                    ApplicationExitInfo.SUBREASON_EXCESSIVE_CPU,
                                    true);
                        }
                    });
                    profile.reportExcessiveCpu();
                }
            }
 
            profile.mLastCpuTime.set(curCpuTime);
        }
    }

4 ActivityManagerService.checkExcessivePowerUsageLPr

检查CPU使用时间除以距离上次检查的时间的百分比是否超过阈值

private boolean checkExcessivePowerUsageLPr(final long uptimeSince, boolean doCpuKills,
            final long cputimeUsed, final String processName, final String description,
            final int cpuLimit, final ProcessRecord app) {
        ...
        // 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) {
            //如果CPU使用时间超过阈值(CPU使用时间除以距离上次检查的时间,cpuLimit可以看做百分比)
            if (((cputimeUsed * 100) / uptimeSince) >= cpuLimit) {
                mBatteryStatsService.reportExcessiveCpu(app.info.uid, app.processName,
                        uptimeSince, cputimeUsed);
                app.getPkgList().forEachPackageProcessStats(holder -> {
                    final ProcessState state = holder.state;
                    FrameworkStatsLog.write(
                            FrameworkStatsLog.EXCESSIVE_CPU_USAGE_REPORTED,
                            app.info.uid,
                            processName,
                            state != null ? state.getPackage() : app.info.packageName,
                            holder.appVersion);
                });
                return true;
            }
        }
        return false;
    }

四:一些想法

1.轮询机制修改太短是否会更加消耗资源,适得其反。(高手课中好像有讲相关的设计)

2.初步可以修改参数
173   private static final long DEFAULT_POWER_CHECK_INTERVAL = ((DEBUG_POWER_QUICK ||XXX)) ? 1 : 5) * 60*1000;
174   private static final int DEFAULT_POWER_CHECK_MAX_CPU_1 = XXX ? 25*3 : 25;
175   private static final int DEFAULT_POWER_CHECK_MAX_CPU_2 = XXX ? 25*3 : 25;
176   private static final int DEFAULT_POWER_CHECK_MAX_CPU_3 = XXX? 10*3 : 10;
177   private static final int DEFAULT_POWER_CHECK_MAX_CPU_4 = XXX? 2*3 : 2;

但更多的是要理解进程何时变为非重要进程。

3.在修改参数的基础上,针对重要应用,是否可以定制cpu使用量,既保证整机性能又满足用户使用。

参考:

Android原生限制后台进程使用CPU机制(AndroidU)_安卓源码禁止app后台运行-CSDN博客

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值