Android Sprd省电管理(五)app 待机网络管理

待机数据联网,会控制应用后台数据访问的频率,从而降低待机功耗。针对的是应用后台频繁访问网络的优化。

待机网络功耗优化,首先需要将捕捉app的状态

在framework中有这样一个binder IUidObserver

oneway interface IUidObserver {
    /**
     * General report of a state change of an uid.
     *
     * @param uid The uid for which the state change is being reported.
     * @param procState The updated process state for the uid.
     * @param procStateSeq The sequence no. associated with process state change of the uid,
     *                     see UidRecord.procStateSeq for details.
     */
    void onUidStateChanged(int uid, int procState, long procStateSeq);

    /**
     * Report that there are no longer any processes running for a uid.
     */
    void onUidGone(int uid, boolean disabled);

    /**
     * Report that a uid is now active (no longer idle).
     */
    void onUidActive(int uid);

    /**
     * Report that a uid is idle -- it has either been running in the background for
     * a sufficient period of time, or all of its processes have gone away.
     */
    void onUidIdle(int uid, boolean disabled);

    /**
     * Report when the cached state of a uid has changed.
     * If true, a uid has become cached -- that is, it has some active processes that are
     * all in the cached state.  It should be doing as little as possible at this point.
     * If false, that a uid is no longer cached.  This will only be called after
     * onUidCached() has been reported true.  It will happen when either one of its actively
     * running processes is no longer cached, or it no longer has any actively running processes.
     */
    void onUidCachedChanged(int uid, boolean cached);
}

展讯的方案是监听onUidGone这个方法,为啥不用onUidIdle,我还没理解,我们就暂时这么理解就是当调用到onUidGone的时候,说明app已经进入adle模式,下面我拿就接着onUidGone分析

PowerController.java-->onUidGone()

        @Override public void onUidGone(int uid, boolean disabled) throws RemoteException {
            synchronized (mUidStateLock) {
                removeUidStateLocked(uid);
            }
            mAppStateInfoCollector.removeUidState(uid);
        }

PowerController.java-->updateUidStateLocked()

    private void removeUidStateLocked(int uid) {
        final int index = mUidState.indexOfKey(uid);
        if (index >= 0) {
            final int oldUidState = mUidState.valueAt(index);
            mUidState.removeAt(index);
            String appName = null;
            try {
                appName = AppGlobals.getPackageManager().getNameForUid(uid);
            } catch (RemoteException e) {
                // can't happen; package manager is process-local
            }
            if (DEBUG_MORE) Slog.d(TAG, "removeUidStateLocked: packageName:" + appName + ", uid:" + uid + " state : "  + Util.ProcState2Str(oldUidState));

            if ((null != appName) ) {
                msgHandler.sendMessage(msgHandler.obtainMessage(MSG_UID_STATE_CHANGED, uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY, appName));
                // Fot PowerHint
                if (mBackgroundCleanHelper != null) {
                    mBackgroundCleanHelper.noteAppStopped(uid, appName);
                }
            }
        }
    }

发送MSG_UID_STATE_CHANGED

            case MSG_UID_STATE_CHANGED:
                handleProcStateChanged((String)msg.obj, msg.arg1, msg.arg2);
                break;

PowerController.java-->handleProcStateChanged()

    private void handleProcStateChanged(String appName, int uid, int procState) {
        if (DEBUG) Slog.d(TAG, "- handleProcstateChanged() E - packageName:" + appName
            + " uid:" + uid + " procState:" + Util.ProcState2Str(procState));

        if (mAppStateInfoCollector.reportAppProcStateInfo(appName, uid, procState)) {
            // Note: Bug 698133 appIdle cts fail -->BEG
            // Ugly: we have to check if doing cts/gts test
            // is cts/gts test, then
            checkCtsGtsTesting(appName);
            // Note: Bug 698133 appIdle cts fail <--END
        }

        int userId = UserHandle.getUserId(uid);
        AppState appState = mAppStateInfoCollector.getAppState(appName, userId);

        if (appState == null) {
            Slog.w(TAG, "null appState for packageName:" + appName
                + " uid:" + uid + " procState:" + Util.ProcState2Str(procState));
            return;
        }

        // if app is stopped, notify WakelockConstraintHelper
        if (appState.mProcState == ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
            appState.updateAppState(Event.NONE);
            mWakelockConstraintHelper.noteAppStopped(appState);
        }

        mRecogAlgorithm.reportEvent(appName, uid, RecogAlgorithm.EVENT_TYPE_PROC_STATE, procState);

        if (mCharging || mScreenOn)
            return;


        // recode the rxBytes if needed
        // should be called before doing Evaluated time stamp update
        appState.updateAppTrafficStats(false);

        // notify helpers to update time stamp
        updateAppEvaluatedTimeStamp(appState);

        // Note: Bug#695969 Audio Recoder fail --> BEG
        // if new procState is <= PROCESS_STATE_FOREGROUND_SERVICE
        // then update its Notification state
        if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
            appState.updateActiveNotificationState(mContext);
        }
        // Note: Bug#695969 Audio Recoder fail <-- END

        msgHandler.removeMessages(MSG_CHECK);
        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_CHECK));
        cancelAlarmLocked();
    }

发送MSG_CHECK

            case MSG_CHECK:
                checkAllAppStateInfo();
                break;

PowerController.java-->checkAllAppStateInfo()

    private void checkAllAppStateInfo() {
        if (DEBUG) Slog.d(TAG, "- checkAllAppStateInfo() E -");
        if (DEBUG) Slog.d(TAG, "mCharging:" + mCharging + " mScreenOn:" + mScreenOn + " mMobileConnected:" + mMobileConnected);

        //set next check
        //msgHandler.removeMessages(MSG_CHECK);
        //msgHandler.sendMessageDelayed(msgHandler.obtainMessage(MSG_CHECK), CHECK_INTERVAL);
        scheduleAlarmLocked(CHECK_INTERVAL);

        if (mCharging || mScreenOn)
            return;

        checkSystemUpTime();

        boolean bChanged = false;
        // Note:use the same now elapsed time for all the AppStateInfo
        // otherwise, when checking app Parole, some app may have not
        // opportunity to exit app standby.
        long now = SystemClock.elapsedRealtime();

        updatePowerSaveMode();

        try {
            final List<UserInfo> users = mUserManager.getUsers();
            for (int ui = users.size() - 1; ui >= 0; ui--) {
                UserInfo user = users.get(ui);
                if (DEBUG) Slog.d(TAG, "- checkAllAppStateInfo() for user: " + user.id);

                final ArrayMap<String, AppState> appStateInfoList = mAppStateInfoCollector.getAppStateInfoList(user.id);
                for (int i=0;i<appStateInfoList.size();i++) {
                    AppState appState = appStateInfoList.valueAt(i);

                    //let app to be parole
                    mAppIdleHelper.checkAppParole(appState, now);

                    // check app state info
                    if (checkAppStateInfo(appState, now)) {
                        bChanged = true;
                    }
                }
            }
        } catch (Exception e) {
        }

        // note AppidleHelper all check done
        mAppIdleHelper.noteCheckAllAppStateInfoDone();
        // note mWakelockConstraintHelper all check done
        mWakelockConstraintHelper.noteCheckAllAppStateInfoDone();

        //send notification to powerguru & appstandby
        // changed for bug#891620
        //if (bChanged) msgHandler.sendMessage(msgHandler.obtainMessage(MSG_NOTIFY_CHANGED));
        if (bChanged) notifyChanged();

        if (needCheckNetworkConnection(now)) {
            if (DEBUG) Slog.d(TAG, "- checkNetworkConnection() in checkAllAppStateInfo -");
            checkNetworkConnection(true);
        }

        // check doze state
        checkDozeState();
    }

PowerController.java-->notifyChanged()

    private void notifyChanged() {
        if (DEBUG) Slog.d(TAG, "- notifyChanged() E -");

        for (int i = 0; i < mHelpers.size(); i++) {
            PowerSaveHelper helper = mHelpers.get(i);
            helper.applyConstrain();
        }
    }

AppIdleHelper 继承PowerSaveHelper

AppIdleHelper.java-->applyConstrain()

    @Override
    void applyConstrain() {

        for (int index=mNewStandbyListForUsers.size()-1; index>=0; index--) {
            ArrayMap<String, Integer> mNewStandbyList = mNewStandbyListForUsers.valueAt(index);

            for (int i=0;i<mNewStandbyList.size();i++) {
                try {
                    if (DEBUG) Slog.d(TAG, "packageName:" + mNewStandbyList.keyAt(i)
                        + " userId:" + mNewStandbyList.valueAt(i) + " enter standby");
                    int userId = mNewStandbyList.valueAt(i);
                    setAppInactive(mNewStandbyList.keyAt(i), true, userId);
                    updateAppStandbyState(mNewStandbyList.keyAt(i), true, userId);
                } catch (Exception e) {
                    // fall through
                }
            }
            mNewStandbyList.clear();

        }
    }

AppIdleHelper.java-->setAppInactive()

    private void setAppInactive(String packageName, boolean idle, int userId) {
        if (!mPowerControllerAppIdleEnabled || mUsageStatsInternal == null) return;

        mUsageStatsInternal.setAppInactive(packageName, idle, userId);
    }

UsageStatsManagerInternal是一个抽象类,UsageStatsService的内部类LocalService继承了UsageStatsManagerInternal,UsageStatsService是一个Android私有service,用于统计应用使用情况,主要作用是收集用户使用每一个APP的频率、使用时常。

UsageStatsService.java-->LocalService-->setAppInactive()

        @Override
        public void setAppInactive(String packageName, boolean idle, int userId) {
            if (mPowerControllerHelper != null)
                mPowerControllerHelper.setAppInactive(packageName, idle, userId);
        }

UsageStatsService.java-->setAppInactive()

        public void setAppInactive(String packageName, boolean idle, int userId) {
            try {
                PackageInfo pi = AppGlobals.getPackageManager()
                        .getPackageInfo(packageName, 0, userId);
                if (pi == null) return;
                UsageStatsService.this.setAppIdleAsync(packageName, idle, userId);
                setAppForceIdleFlag(packageName, idle, userId);
            } catch (RemoteException re) {
            } finally {
            }
        }


UsageStatsService.java-->setAppIdleAsync()

    void setAppIdleAsync(String packageName, boolean idle, int userId) {
        if (packageName == null) return;

        mHandler.obtainMessage(MSG_FORCE_IDLE_STATE, userId, idle ? 1 : 0, packageName)
                .sendToTarget();
    }

发送MSG_FORCE_IDLE_STATE


                case MSG_FORCE_IDLE_STATE:
                    forceIdleState((String) msg.obj, msg.arg1, msg.arg2 == 1);
                    break;

UsageStatsService.java-->forceIdleState()

    void forceIdleState(String packageName, int userId, boolean idle) {
        final int appId = getAppId(packageName);
        if (appId < 0) return;
        final long elapsedRealtime = SystemClock.elapsedRealtime();

        final boolean previouslyIdle = isAppIdleFiltered(packageName, appId,
                userId, elapsedRealtime);
        synchronized (mAppIdleLock) {
            mAppIdleHistory.setIdle(packageName, userId, idle, elapsedRealtime);
        }
        final boolean stillIdle = isAppIdleFiltered(packageName, appId,
                userId, elapsedRealtime);
        // Inform listeners if necessary
        if (previouslyIdle != stillIdle) {
            mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
                    /* idle = */ stillIdle ? 1 : 0, packageName));
            if (!stillIdle) {
                notifyBatteryStats(packageName, userId, idle);
            }
        }
    }

发送MSG_INFORM_LISTENERS

                case MSG_INFORM_LISTENERS:
                    informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
                    break;

UsageStatsService.java-->informListeners()

    void informListeners(String packageName, int userId, boolean isIdle) {
        for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
            listener.onAppIdleStateChanged(packageName, userId, isIdle);
        }
    }

NetworkPolicyManagerService的内部类AppIdleStateChangeListener继承了UsageStatsManagerInternal.AppIdleStateChangeListener

    private class AppIdleStateChangeListener
            extends UsageStatsManagerInternal.AppIdleStateChangeListener {

        @Override
        public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
            try {
                final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
                        PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
                if (LOGV) Log.v(TAG, "onAppIdleStateChanged(): uid=" + uid + ", idle=" + idle);
                synchronized (mUidRulesFirstLock) {
                    updateRuleForAppIdleUL(uid);
                    updateRulesForPowerRestrictionsUL(uid);
                }
            } catch (NameNotFoundException nnfe) {
            }
        }
        ......
    }

NetworkPolicyManagerService.java-->updateRuleForAppIdleUL()

    void updateRuleForAppIdleUL(int uid) {
        if (!isUidValidForBlacklistRules(uid)) return;

        // NOTE: Bug #693427 low power Feature BEG -->
        boolean ignoreProcState = PowerControllerHelper.getInstance(mContext).ignoreProcStateForAppIdle();
        // <-- NOTE: Bug #693427 low power Feature END

        if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
            Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRuleForAppIdleUL: " + uid );
        }
        try {
            int appId = UserHandle.getAppId(uid);
            if (!mPowerSaveTempWhitelistAppIds.get(appId) && isUidIdle(uid)
                    && (ignoreProcState || !isUidForegroundOnRestrictPowerUL(uid))) {
                setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DENY);
            } else {
                setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, FIREWALL_RULE_DEFAULT);
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
        }
    }

NetworkPolicyManagerService.java-->setUidFirewallRule()

    /**
     * Add or remove a uid to the firewall blacklist for all network ifaces.
     */
    private void setUidFirewallRule(int chain, int uid, int rule) {
        if (Trace.isTagEnabled(Trace.TRACE_TAG_NETWORK)) {
            Trace.traceBegin(Trace.TRACE_TAG_NETWORK,
                    "setUidFirewallRule: " + chain + "/" + uid + "/" + rule);
        }
        try {
            if (chain == FIREWALL_CHAIN_DOZABLE) {
                mUidFirewallDozableRules.put(uid, rule);
            } else if (chain == FIREWALL_CHAIN_STANDBY) {
                mUidFirewallStandbyRules.put(uid, rule);
            } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
                mUidFirewallPowerSaveRules.put(uid, rule);
            }

            try {
                mNetworkManager.setFirewallUidRule(chain, uid, rule);
            } catch (IllegalStateException e) {
                Log.wtf(TAG, "problem setting firewall uid rules", e);
            } catch (RemoteException e) {
                // ignored; service lives in system_server
            }
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
        }
    }

NetworkManagementService.java-->setFirewallUidRule()


    @Override
    public void setFirewallUidRule(int chain, int uid, int rule) {
        enforceSystemUid();
        synchronized (mQuotaLock) {
            setFirewallUidRuleLocked(chain, uid, rule);
        }
    }

NetworkManagementService.java-->setFirewallUidRuleLocked()

    private void setFirewallUidRuleLocked(int chain, int uid, int rule) {
        if (updateFirewallUidRuleLocked(chain, uid, rule)) {
            try {
                mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
                        getFirewallRuleName(chain, rule));
            } catch (NativeDaemonConnectorException e) {
                throw e.rethrowAsParcelableException();
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/liu362732346/article/details/86494730