1. 程式人生 > >Android Sprd省電管理(三)鎖屏清理

Android Sprd省電管理(三)鎖屏清理

我們接著上篇 Android Sprd省電管理(二)應用省電模式設定流程,講下鎖屏清理的原理

鎖屏清理簡介:

鎖屏清理目的是減少待機應用從而來減少待機功耗。鎖屏清理是在待機一段時間後才開始進行。
該時間值大於 1min。出於功耗考慮沒有采用可喚醒的 alarm 來設定該 1min 定時器。而是採
用非可喚醒的 alarm。而非可喚醒 alarm 需要有可喚醒 alarm 才會觸發,因此這會導致開始
清理的時間遠大於 1min。但一般 10 分鐘內都會有可喚醒 alarm,也就是 10 分鐘內會進行清理

一些應用不會被清理,即使在已經被設定為清理的情況下。這些應用包括:
a) 輸入法應用;
b) 預設的系統服務應用,如桌布服務應用,預設簡訊服務應用等;
c) 當前滅屏前可見的應用;

d)正在播放音樂的應用;

e) 正在下載的應用;
f) 內建系統應用;

上述這些型別的應用不能清理,清理後會導致使用上的體驗問題。

鎖屏清理流程:

在PowerContorller.java中註冊了一些裝置狀態變化的廣播

 private void registerForBroadcasts() {
        IntentFilter intentFilter = new IntentFilter();
        //亮屏廣播
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        //滅屏廣播
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
        intentFilter.addAction(ACTION_CHECK_APPSTATE);
        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
        intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
        intentFilter.addAction(INTENT_SCHEDULEMODE_ALARM);

        mContext.registerReceiver(
            new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (ACTION_CHECK_APPSTATE.equals(action)) {
                        msgHandler.removeMessages(MSG_CHECK);
                        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_CHECK));

                        // for PowerGuru Interval upadate
                        if (mPowerGuruAligningStart) {
                            msgHandler.removeMessages(MSG_UPDATE_POWERGURU_INTERVAL);
                            msgHandler.sendMessage(msgHandler.obtainMessage(MSG_UPDATE_POWERGURU_INTERVAL));
                        }
                    } else if(Intent.ACTION_BOOT_COMPLETED.equals(action)) {
                        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_BOOT_COMPLETED));
                    } else if(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(action)) {
                        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_WHITELIST_CHANGED));
                    } else if(INTENT_SCHEDULEMODE_ALARM.equals(action)) {
                        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_SCHEDULEMODE_ALARM));
                    } else {
//亮滅屏時,傳送MSG_DEVICE_STATE_CHANGED
                        msgHandler.sendMessage(msgHandler.obtainMessage(MSG_DEVICE_STATE_CHANGED, intent));
                    }
                }
            }, intentFilter);
            case MSG_DEVICE_STATE_CHANGED:
                handleDeviceStateChanged((Intent)msg.obj);
                break;

PowerContorller.java-->handleDeviceStateChanged()

    private void handleDeviceStateChanged(Intent intent) {
        String action = intent.getAction();
        boolean oldScreenOn = mScreenOn;
        boolean oldMobileConnected = mMobileConnected;
        boolean oldCharging = mCharging;

        if (DEBUG) Slog.d(TAG, "- handleDeviceStateChanged() E -, action: " + action);

        if (action.equals(Intent.ACTION_SCREEN_ON)) {
            mScreenOn = true;
        } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
            mScreenOn = false;
        } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
            boolean bNoConnection = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
            if (!bNoConnection) {
                int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE);
                mMobileConnected = ConnectivityManager.isNetworkTypeMobile(networkType);
                mWifiConnected = ConnectivityManager.isNetworkTypeWifi(networkType);
            } else {
                mMobileConnected = false;
                mWifiConnected = false;
            }
        } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
            int pluggedType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
            mCharging = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0));
            if (DEBUG) Slog.d(TAG, "pluggedType:" + pluggedType + " mCharging:" + mCharging);
            updateBatteryLevelLow(false);
            updatePowerSaveMode();
        } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
            try {
                notifyDozeStateChanged();
            } catch (Exception e) {
                // fall through
            }
            return;
        }

        if (DEBUG_MORE) Slog.d(TAG, "handleDeviceStateChanged: mCharging:" + mCharging
            + " mScreenOn:" + mScreenOn + " mMobileConnected:" + mMobileConnected);

        boolean bScreenChanged = (oldScreenOn != mScreenOn);
        boolean bConnectionChanged = (oldMobileConnected != mMobileConnected);
        boolean bChargingChanged = (oldCharging != mCharging);

        if (DEBUG) Slog.d(TAG, "handleDeviceStateChanged: bScreenChanged:" + bScreenChanged
            + " bConnectionChanged:" + bConnectionChanged + " bChargingChanged:" + bChargingChanged);

        if (bScreenChanged || bConnectionChanged || bChargingChanged) {
            checkPowerGuruInterval();
        }
        if (bScreenChanged || bChargingChanged) {
            updateAppStateInfoForDeviceStateChanged();
        }

        if (bScreenChanged)
            mRecogAlgorithm.reportDeviceState(RecogAlgorithm.DEVICE_STATE_TYPE_SCREEN, mScreenOn);

        if (bChargingChanged) {
            mRecogAlgorithm.reportDeviceState(RecogAlgorithm.DEVICE_STATE_TYPE_CHARGING, mCharging);
        }

        // if in standby state, trigger a delay MSG_CHECK operation
        if (!mScreenOn && !mCharging) {
            msgHandler.removeMessages(MSG_CHECK);
            msgHandler.sendMessageDelayed(msgHandler.obtainMessage(MSG_CHECK), SCREENOFF_CHECK_INTERVAL);
        }
    }

重點看MSG_CHECK

            case MSG_CHECK:
                checkAllAppStateInfo();
                break;

PowerContorller.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();
    }

PowerContorller.java-->checkAppStateInfo()

    private boolean checkAppStateInfo(AppState appState, final long nowELAPSED) {
        boolean bChanged = false;
        // check app state info
        for (int i = 0; i < mHelpers.size(); i++) {
            PowerSaveHelper helper = mHelpers.get(i);
            if (helper.checkAppStateInfo(appState, nowELAPSED)) {
                bChanged = true;
            }
        }

        return bChanged;
    }

BackgroundCleanHelper.java -->checkAppStateInfo()

    /*
     * check this app should be constrained or not
     * return true if this app should be constrained
     * others return false
     */
    boolean checkAppStateInfo(AppState appState, final long nowELAPSED) {
        ArrayMap<String, Integer> mForceStopAppList = getForceStopAppList(appState.mUserId);

        boolean bChanged = false;

        if (canBeConstrained(appState)) {
            bChanged = true;
            //可以被清理的程序放入到mForceStopAppList
            if (!mForceStopAppList.containsKey(appState.mPackageName)) {
                mForceStopAppList.put(appState.mPackageName, appState.mUserId);
                if (DEBUG) Slog.d(TAG, "checkAppStateInfo(), add " + appState.mPackageName + " to forcestop list");
            }
        } else {
            // if already put it in mForceStopAppList, just remove
            mForceStopAppList.remove(appState.mPackageName);
        }

        return bChanged;
    }

現在就到核心方法了canBeConstrained(),我們來重點看下

 boolean canBeConstrained(AppState appState) {

        // if this function is disabled, just return false
        if (!mEnabled) return false;

        // set bgclean timer
        long delayMs = SystemClock.elapsedRealtime() - mStandbyStartTime - DOCLEAN_TIMEOUT;
        if (delayMs < 0) {
            if (!mAlarmSet) {
                if (DEBUG) Slog.d(TAG, "canBeConstrained(), set alarm");
                // not use wake up alarm, otherwise a cts case of sensor will fail.
                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
                    mStandbyStartTime + DOCLEAN_TIMEOUT, TAG, mAlarmListener, mHandler);
                mAlarmSet = true;
            }
            return false;
        }

        // not a system app
        if (isSystemApp(appState)) { // system app
            return false;
        }

        // app not exist
        if ((appState.mProcState == ActivityManager.PROCESS_STATE_CACHED_EMPTY && Event.NONE == appState.mState)
            || appState.mProcState == ActivityManager.PROCESS_STATE_NONEXISTENT) {
            return false;
        }

        // avoid kill input method
        if (appState.mIsEnabledInputMethod)
            return false;

        if (isImportantPrefferedApp(appState.mPackageName))
            return false;

        boolean isVisible = false;
        int index = mVisibleAppList.indexOf(appState.mPackageName);
        if (index >= 0) {
            isVisible = true;
        }
        // not a visible app
        if (isVisible) {
            return false;
        }

        // playing music App can not be constrained
        if (isPlayingMusic(appState)) {
            if (DEBUG) Slog.d(TAG, "canBeConstrained: " + appState.mPackageName + " Music is playing");
            return false;
        }

        // doing download App can not be constrained
        if (isDoingDownload(appState)) {
            if (DEBUG) Slog.d(TAG, "canBeConstrained: " + appState.mPackageName
                + " Doing Download");
            return false;
        }

        /** @hide Process is in the background, but it can't restore its state so we want
         * to try to avoid killing it. */
        if (appState.mProcState == ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
            return false;
        }

        // not app in whitelist
        if (inCommonWhiteAppList(appState.mPackageName)) {
            return false;
        }

        if (mLockScreen_WhiteList.contains(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "bgclean CanBeConstrained: " + appState.mPackageName + " in my lockscreen whitelist");
            return false;
        } else if (mLockScreen_BlackList.contains(appState.mPackageName)) {
            if (DEBUG) Slog.d(TAG, "bgclean CanBeConstrained: " + appState.mPackageName + " in my lockscreen blacklist");
            return true;
        }

        // this app is avoid killing
        if (appState.mAvoidKilling) return false;

        // message App can not be constrained
        // for bug#787547 don't kill preset message app
        if (isMessageApp(appState)
            ||mAbsDeviceIdleController.isInPresetWhiteAppList(appState.mPackageName)
            ) {
            if (DEBUG) Slog.d(TAG, "canBeConstrained: " + appState.mPackageName + " Message App");
            return false;
        }

        // in low power mode, we will clean more bg app
        if (PowerManagerEx.MODE_LOWPOWER == mPowerSaveMode) {
            if (DEBUG) Slog.d(TAG, "canBeConstrained, low power mode clean, appname: " + appState.mPackageName + ", time diff: " + (SystemClock.elapsedRealtime() - mStandbyStartTime)
                + ", procState: " + appState.mProcState);
            if (LOWPOWER_DOCLEAN_THRESHOLD <= SystemClock.elapsedRealtime() - mStandbyStartTime) {
                if (appState.mProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
                    if (DEBUG) Slog.d(TAG, "canBeConstrained: low power mode clean, " + appState.mPackageName);
                    return true;
                }
            }
        }

        // doing download App can not be constrained
        if (isDoingDownload(appState)) {
            if (DEBUG) Slog.d(TAG, "canBeConstrained: " + appState.mPackageName
                + " Doing Download (mUsedTimeSliceCount:" + appState.mUsedTimeSliceCount + ")");
            // download is checked using a time slice (default 30s)
            // if the count of time slice using to complete detecting download
            // is >= 1, then we can be sure that user use this app doing download before standby
            // in this case, we will avoid kill this app
            if (appState.mUsedTimeSliceCount >=1 ) {
                appState.mAvoidKilling = true;
            }
            return false;
        }

        long nowELAPSED = SystemClock.elapsedRealtime();
        long now = System.currentTimeMillis(); // wall time
        long fromBootup = now - nowELAPSED; // wall time
        long idleDuration = 0;
        long idleDurationBeforeStandby = 0;
        boolean hasLaunched = false;
        boolean hasNotification = false;
        boolean mayPlayingMusic = false;
        boolean launcherApp = isLauncherApp(appState.mPackageName);

        // FixMe: if we has more exact method to jude app playing music, then we don't need to do this
        mayPlayingMusic = mayBePlayingMusic(appState);

        if (DEBUG) Slog.d(TAG, "pkg: " + appState.mPackageName
            + " flags:" + Integer.toHexString(appState.mFlags)
            + " ProcState:" + Util.ProcState2Str(appState.mProcState));

        if (appState.mLastLaunchTime > 0) hasLaunched = true;
        idleDuration = (appState.mLastTimeUsed > 0 ? (nowELAPSED -appState.mLastTimeUsed) : -1);
        idleDurationBeforeStandby = (mStandbyStartTime > appState.mLastTimeUsed ? (mStandbyStartTime -appState.mLastTimeUsed) : 0);

        hasNotification = hasActiveNotification(appState);

        if (DEBUG) Slog.d(TAG, "STATE: pkg:" + appState.mPackageName
            + " idle for:" + idleDuration
            + " idleDurationBeforeStandby:" + idleDurationBeforeStandby
            + " hasLaunched:" + hasLaunched
            + " isVisable:" + isVisible
            + " hasNotification:" + hasNotification
            + " mayPlayingMusic:" + mayPlayingMusic
            + " launcherApp:" + launcherApp);


        // if app is launched by user
        // and may be playing music, then don't kill this app
        if (hasLaunched && mayPlayingMusic) {
            return false;
        }

        /*
         * 7. ((app not lauched by user  && app has not notification) ||
         *      (app not launched by user && app has notification && idle time > 1 h after standby) )
         */
        if ((!hasLaunched && !hasNotification)
            || (!hasLaunched && hasNotification && idleDuration > (idleDurationBeforeStandby + FORCE_STOP_IDLE_THRESHOLD1) )
            ) {

            return true;
        }

        /*
         * 8. ((app launched by user && app has not notification && idle time > 2h) ||
         *      (app launched by user && app has notification && && idle time > 4h after standby))
         */
        if (hasLaunched) {
            int currentActiveLaunchedCount = mAppStateInfoCollector.getCountOfActiveLaunchedApps(mCurrentUserId);
            if (DEBUG) Slog.d(TAG, "currentActiveLaunchedCount:" + currentActiveLaunchedCount);

            if (!launcherApp && currentActiveLaunchedCount > MAX_LAUNCHED_APP_KEEP) {
                if ((!hasNotification && idleDuration > ( FORCE_STOP_IDLE_THRESHOLD2))
                ||  (hasNotification && !appState.mHasNoClearNotification
                      && idleDuration > ( idleDurationBeforeStandby + FORCE_STOP_IDLE_THRESHOLD3))
                ) {
                    return true;
                }
            }
        }

        return false;
    }

isSystemApp(),判斷是否是系統應用

    private boolean isSystemApp(AppState appState) {
        if (appState != null) {
            return ((appState.mFlags & (ApplicationInfo.FLAG_UPDATED_SYSTEM_APP | ApplicationInfo.FLAG_SYSTEM)) != 0
                || appState.mFlags == 0);
        } else {
            return true; // default
        }
    }

appState.mIsEnabledInputMethod 判斷是否是輸入法

我們看下這個值是怎麼設定的

    

        AppState retVal = new AppState(packageName, userId, uid, stateEvent, procState, flags);

        // check if is input method
        retVal.mIsEnabledInputMethod = isEnabledIMEApp(packageName);

    // if this app is a input Method
    private boolean isEnabledIMEApp(String pkgName){
        if (pkgName == null) return false;
        IInputMethodManager service = IInputMethodManager.Stub.asInterface(
            ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
        List<InputMethodInfo> inputMethods;
        try {
            inputMethods = service.getEnabledInputMethodList();
        } catch (RemoteException e) {
            return false;
        }
        if (inputMethods == null || inputMethods.size() == 0) return false;
        for (InputMethodInfo info : inputMethods){
            if (info == null || info.getPackageName() == null) continue;
            if (info.getPackageName().equals(pkgName)) return true;
        }
        return false;
    }

isVisible判斷是否有啟動的應用

        boolean isVisible = false;
        int index = mVisibleAppList.indexOf(appState.mPackageName);
        if (index >= 0) {
            isVisible = true;
        }
        // not a visible app
        if (isVisible) {
            return false;
        }

從程式碼可以看出isVisible是通過mVisibleAppList判斷的

    private void updateVisibleActivities() {
        try {
            // Clear first
            mVisibleAppList.clear();

            List<IBinder> activityTokens = null;

            // Let's get top activities from all visible stacks
            activityTokens = LocalServices.getService(ActivityManagerInternal.class).getTopVisibleActivities();
            final int count = activityTokens.size();

            for (int i = 0; i < count; i++) {
                IBinder topActivity =  activityTokens.get(i);
                try {
                    String  packageName = mActivityManager.getPackageForToken(topActivity);
                    if (packageName != null) {
                        mVisibleAppList.add(packageName);
                        Slog.d(TAG, "VisibleActivities:" + packageName);
                    }
                } catch (RemoteException e) {
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        Slog.d(TAG, "updateVisibleActivities done");
    }

isPlayingMusic 判斷應用是否正在播放音樂

這個流程看了下有點兒負責,等有時間單獨寫個總結分析

isDoingDownload 判斷應用是否正在下載

 private boolean isAppDoingDownloadInternal(AppState state) {
        int procState = state.mProcState;

        //if (procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE)
        //    return false;

        boolean doingDownload = false;
        if (state.mRxBytesWhenStartEvaluated > 0) {
            long now = SystemClock.elapsedRealtime();
            long currentRxBytes = TrafficStats.getUidRxBytes(state.mUid);
            long secondsSpended = (now - state.mTimeStampForRxBytes)/1000;
            if (DEBUG) Slog.d(TAG, "uid:" + state.mUid + " packageName:" + state.mPackageName
                + " currentRxBytes:" + currentRxBytes + " startRxBytes:" + state.mRxBytesWhenStartEvaluated
                + " timespended: " + secondsSpended + " avgRate:" + (currentRxBytes - state.mRxBytesWhenStartEvaluated)/(secondsSpended+1));
            if (currentRxBytes - state.mRxBytesWhenStartEvaluated
                > (MIN_DATA_RATE * secondsSpended) || (secondsSpended < DOWNLOAD_CHECKING_MIN_TIME_SPAN))
                doingDownload = true;

            if (doingDownload && secondsSpended > DOWNLOAD_CHECKING_MIN_TIME_SPAN) {
                long systemUpDuration = secondsSpended*1000;
                if (mLastSystemUpTimeStamp > 0)
                    systemUpDuration = (now - mLastSystemUpTimeStamp);
                if (DEBUG) Slog.d(TAG, "systemUpDuration:" + systemUpDuration + " secondsSpended:" + secondsSpended);

                if (systemUpDuration < (secondsSpended - 2 *SYSTEM_UP_CHECK_INTERVAL)) {
                    if (DEBUG) Slog.d(TAG, "systemUpDuration:" + systemUpDuration + "but secondsSpended:" + secondsSpended
                        + " clear download flag!!");
                    doingDownload = false;
                }
            }

            //Download state changed!!
            if (state.mDoingDownload != doingDownload) {
                mDownloadChangeCount++;
                msgHandler.sendMessage(msgHandler.obtainMessage(MSG_DOWNLOAD_STATE_CHANGED, (doingDownload?1:0), 0, state));
            }

            if (doingDownload) {
                if (secondsSpended >= DOWNLOAD_CHECKING_MIN_TIME_SPAN) {
                    state.mRxBytesWhenStartEvaluated = currentRxBytes;
                    state.mTimeStampForRxBytes = SystemClock.elapsedRealtime();
                    state.mUsedTimeSliceCount++;
                }
                return true;
            }
        }
        return false;
    }

canBeConstrained()分析完後,再回頭看看checkAllAppStateInfo()-->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();
        }
    }

BackgroundCleanHelper.java-->notifyChanged()

    void applyConstrain() {

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

            try {
                for (int i=0;i<mForceStopAppList.size();i++) {
                    String pkgName =  mForceStopAppList.keyAt(i);
                    int userId = mForceStopAppList.valueAt(i);
                    try {
                        //呼叫forceStopPackage清理程序
                        mActivityManager.forceStopPackage(pkgName, userId);
                        AppState appState = mAppStateInfoCollector.getAppState(pkgName, userId);
                        if (appState != null) {
                            // do some cleaning for appState
                            appState.clearLaunchInfo();
                        } else {
                            Slog.w(TAG, "null appState for " + pkgName + " userId:" + userId);
                        }
                        Slog.d(TAG, "force stop:" + pkgName + " userId:" + userId);

                        ArrayMap<String, Integer> mStoppedAppList = getStoppedAppList(userId);
                        // add to stopped app list
                        mStoppedAppList.put(pkgName, userId);

                    } catch (RemoteException e) {
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            mForceStopAppList.clear();