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();

       

猜你喜欢

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