1. 程式人生 > >Android Sprd省電管理(四)自啟動和關聯啟動管理

Android Sprd省電管理(四)自啟動和關聯啟動管理

自啟動和管理啟動管理介紹

自啟動管理用於管理應用的開機自啟動/後臺自啟動/關聯自啟動。應用自啟動的管理,以包名(應
用名)進行限制,不區分 user(使用者)。

(1)自啟動
指開機自啟動和後臺自啟動。應用可以監聽系統的一些開機廣播,從而在系統開機後自動進行啟動。
同時應用也可以監聽系統的任何廣播,如網路連線的廣播,從而在網路連線上的時候,進行自啟動。
(2)關聯啟動
關聯啟動指不同的應用之間進行互起。這裡指的是,該應用被其他應用後臺啟動。

流程分析

1)自啟動reason

    private static final String REASON_START_SERVICE = "start-service";
    private static final String REASON_BIND_SERVICE = "bind-service";
    private static final String REASON_CONTENT_PROVIDER = "contentprovider";
    private static final String REASON_BROADCAST = "send-broadcast";
    private static final String REASON_START_ACTIVITY = "start-activity";

 

1.1 start-activity

在ActivityStarter.java-->startActivity()判斷是否是異常啟動

    private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, TaskRecord inTask) {
              
        .......
        String targetPkg = null;
        int targetUid = aInfo != null ? aInfo.applicationInfo.uid : 0;
        if (intent.getComponent() != null) targetPkg = intent.getComponent().getPackageName();
        if(!mService.judgeStartAllowLocked(intent, targetPkg, targetUid, callingUid, callingPackage, "start-activity")){
            return ActivityManager.START_INTENT_NOT_RESOLVED;
        }
        .......
}

1.2 start-service

在ActiveServices.java-->startServiceLocked()

    ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        ......
                int targetUid = r.appInfo != null ? r.appInfo.uid : 0 ;
        if(!mAm.judgeStartAllowLocked(service, r.packageName, targetUid, callingUid, callingPackage,"start-service")) {
            return null;
        }
        ......

1.3 bind-service

在ActiveServices.java-->bindServiceLocked()

    int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String callingPackage, final int userId) throws TransactionTooLargeException {
          ......
                  String targetPkg = s != null ? s.packageName : null;
        int targetUid = (s != null && s.appInfo != null) ? s.appInfo.uid : 0;
        int callingUid = (callerApp != null && callerApp.info != null) ? callerApp.info.uid : 0;
        if(!mAm.judgeStartAllowLocked(service, targetPkg, targetUid, callingUid, callingPackage,"bind-service")) {
            return 0;
        }
          ......

1.4 send-broadcast

final void processNextBroadcast(boolean fromMsg) {
        ......
                        skip = skip || !mService.judgeStartAllowLocked(r.intent, info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.applicationInfo.uid, r.callingUid, r.callerPackage,"send-broadcast");
        ......
}

1.5 contentprovider

ActivityManagerService.java -->getContentProviderImpl()


    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
        ContentProviderRecord cpr;
        ......
                        String targetPkg = (cpr != null && cpr.appInfo != null) ? cpr.appInfo.packageName : null;
                int targetUid = (cpr != null && cpr.appInfo != null) ? cpr.appInfo.uid : 0;
                if (r != null && r.info != null) {
                    String callingPackage = r.info.packageName;
                    int callerUid = r.info.uid;
                    if(!judgeStartAllowLocked(null, targetPkg, targetUid, callerUid, callingPackage,"contentprovider")) {
                        return null;
                    }
                }
        ......

可以看出自啟動的攔截,就是在四大元件啟動流程中進行的

2)judgeStartAllowLocked()流程分析

ActivityManagerServerEx.java-->judgeStartAllowLocked()

    protected boolean judgeStartAllowLocked(Intent intent, String targetPkg, int targetUid,
        int callingUid, String callingPackage, String reason) {

        boolean allowed = true;
        if (allowed && mPowerControllerInternal != null) {
            try {
                allowed = mPowerControllerInternal.judgeAppLaunchAllowed(intent, targetPkg, targetUid, callingUid, callingPackage, reason);
            } catch (Exception e) {}
        }
        

BackgroundCleanHelper.java-->judgeAppLaunchAllowed()

     boolean judgeAppLaunchAllowed(Intent intent, String targetApp, int targetUid,
            int callerUid, String callerApp, String reason) {
        mPowerHintSceneForGts.noteAppLaunched(targetApp, callerApp, callerUid);

        boolean ret = judgeAppLaunchAllowedInternal(intent, targetApp, targetUid, callerUid, callerApp, reason);
        if (mCurrentUserId == 0 && ret && targetApp != null) {
            if (!targetApp.equals(callerApp) && !mFirstCallerAppList.containsKey(targetApp)
                && isInstalledApp(targetApp, 0)) {
                mFirstCallerAppList.put(targetApp, new CallerAppInfo(callerApp, callerUid, reason));
            }
        }
        return ret;

BackgroundCleanHelper.java-->judgeAppLaunchAllowedInternal()

/*
     * Third app can not self started:
     * 1. not allow system broadcast from "systemserver" or "com.android.systemui"
     * 2. not allow start service from ""com.android.shell"
     * 3. not allow background app to launch other third party app
     * 4. not allow self started third party app to start other third party app
     * 5. not allow third party app to start other third party app during standby
     *
     * Note: This api is call from AMS in other threads and may be in variable calling context
     *  SO BE CAREFULL : avoid call other system API that may hold lock. Otherwise, a deadlock may HAPPEN
     */
     boolean judgeAppLaunchAllowedInternal(Intent intent, String targetApp, int targetUid,
            int callerUid, String callerApp, String reason) {

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

        if (DEBUG_MORE) Slog.d(TAG,"judgeAppLaunchAllowed : "+targetApp+"(uid:" + targetUid
            + "), callingPackage = "+callerApp+"(uid:" + callerUid + "), reason = "+reason);
        if (DEBUG_MORE && intent != null) Slog.d(TAG,"judgeAppLaunchAllowed : intent action:" + intent);

        if (targetApp == null) return true;

        // bug#768670
        if (handleStartServiceStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
            return true;
        }

        if (handleBindServiceStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
            return true;
        }

        if (handleContentProviderStartAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
            return true;
        }

        //handle inputmethod
        if (isLaunchingIMEApp(intent, targetApp, targetUid, callerApp, reason)) {
            return true;
        }

        if (handleBroadcastAction(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
            return true;
        }

        //handle speech recognition
        if (isRecognizerIntent(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
            return true;
        }

        // allow cts app to start any other app
        // allow autotest app
        if (Util.isCts(callerApp) || isAutoTest(callerUid, callerApp, targetApp)) {
            return true;
        }

        // check deny for ultra saving mode
        //if (denyBecauseOfUltraSavingMode(intent, targetApp, targetUid, callerApp, callerUid, reason)) {
        //    return false;
        //}

        int targetUserId = UserHandle.getUserId(targetUid);
        int callUserId = UserHandle.getUserId(callerUid);
        AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, callUserId);
        AppState targetAppState = mAppStateInfoCollector.getAppState(targetApp, targetUserId);

        // if target app already exist
        /*if (targetAppState != null
            && targetAppState.mProcState < ActivityManager.PROCESS_STATE_CACHED_EMPTY
            && targetAppState.mProcState != ActivityManager.PROCESS_STATE_NONEXISTENT) {*/
        if (isAlreadyStarted(targetAppState)) {
            if (DEBUG_MORE) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": already started!!"
                + " (ProcState:" +  Util.ProcState2Str(targetAppState.mProcState)
                + " mState:" + Util.AppState2Str(targetAppState.mState)
                + ")");
            return true;
        }

        // check system app
        // allow to launch system app
        int launchState = checkLaunchStateByPreset(intent, targetApp, targetUid, callerApp, callerUid, reason);
        if (launchState == LAUNCH_STATE_ALLOW)
            return true;
        else if (launchState == LAUNCH_STATE_DENY)
            return false;

        // check user setting for third-party app(重點)
        launchState = checkLaunchStateByUserSetting(intent, targetApp, targetUid, callerApp, callerUid, reason);
        if (DEBUG_MORE) Slog.d(TAG, "launchState: " + launchState);
        if (launchState == LAUNCH_STATE_ALLOW)
            return true;
        else if (launchState == LAUNCH_STATE_DENY)
            return false;

        // not allow third party app that has been force stopped during standby
        // to be started again
        if (mStandbyStartTime > 0 && isForceStoppedAppDuringStandby(targetApp, targetUid)) {
            if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed (has been force stopped)!!");
            return false;
        }

        // not allow system broadcast to launch third party app
        if ((callerAppState == null ||(callerApp != null && callerApp.equals("android")))
            && REASON_BROADCAST.equals(reason)) {
            if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
            return false;
        }

        // not allow "com.android.systemui" broadcast to launch third party app
        if (callerApp != null && callerApp.equals("com.android.systemui")
            && REASON_BROADCAST.equals(reason)) {
            if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
            return false;
        }

        // allow app to launch itself
        if (targetApp.equals(callerApp)) {
            return true;
        }

        // not allow non-top app to launch other app, except launched by UserActivity
        if (!launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
            if (DEBUG) {
                Slog.d(TAG,"Start Proc : "+targetApp
                    +", callingPackage = "+callerApp
                    + " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
                    +"), reason = "+reason
                    + ": non-UserActivity denyed!!");
            }
            return false;
        }

        // not allow background app to launch other third party app
        if (callerAppState != null && callerAppState.mProcState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
            && !REASON_START_ACTIVITY.equals(reason)) {
            if (DEBUG) {
                Slog.d(TAG,"Start Proc : "+targetApp
                    +", callingPackage = "+callerApp
                    + " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
                    +"), reason = "+reason
                    + ": denyed!!");
            }
            return false;
        }

        // not allow self started third party app to start other third party app
        if (callerAppState != null && callerAppState.mLaunchCount == 0 && !isSystemApp(callerAppState)
            && !REASON_START_ACTIVITY.equals(reason)) {
            if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!!");
            return false;
        }

        // not allow long idle third party app to start other third party app
        if (callerAppState != null && !isSystemApp(callerAppState)
            && callerAppState.mState != Event.MOVE_TO_FOREGROUND
            && callerAppState.mProcState != ActivityManager.PROCESS_STATE_TOP
            && !REASON_START_ACTIVITY.equals(reason)) {

            long nowELAPSED = SystemClock.elapsedRealtime();
            long idleDuration = 0;
            idleDuration = (callerAppState.mLastTimeUsed > 0 ? (nowELAPSED -callerAppState.mLastTimeUsed) : -1);
            if (idleDuration > DENY_START_APP_THRESHOLD) {
                if (DEBUG) Slog.d(TAG,"Start Proc : "+targetApp+", callingPackage = "+callerApp+", reason = "+reason + ": denyed!! long idle");
                return false;
            }
        }


        // not allow third party app to start other third party app during standby
        if (mStandbyStartTime > 0
            && !REASON_START_ACTIVITY.equals(reason)) {
            if (DEBUG) {
                Slog.d(TAG,"Start Proc : "+targetApp
                    +", callingPackage = "+callerApp
                    + " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
                    +"), reason = "+reason
                    + ": denyed during standby!!");
            }
            return false;
        }


        return true;

    }

BackgroundCleanHelper.java-->checkLaunchStateByUserSetting()

private int checkLaunchStateByUserSetting(Intent intent, String targetApp, int targetUid,
            String callerApp, int callerUid, String reason) {

        if (targetApp == null || targetApp.equals(callerApp))
            return LAUNCH_STATE_AUTO;

        boolean launchByOther = autoLaunchByOtherApp(targetApp, targetUid, callerApp, callerUid, reason);

        // allow app in whitelist
        if (inSelfStartWhiteAppList(targetApp)) {
            return LAUNCH_STATE_ALLOW;
        }

        // if in ultrasaving mode, don't allow autostart except apps in ultrasve applist
        if (!launchByOther && (PowerManagerEx.MODE_ULTRASAVING == mPowerSaveMode)
            && (PowerManagerEx.MODE_ULTRASAVING == mNextPowerSaveMode)) {
            List<String> appList = mPowerControllerInternal.getAppList_UltraMode();
            if (!appList.contains(targetApp)) {
                if (DEBUG) Slog.d(TAG, "app: " + targetApp + " in applist of ultramode, refuse to autostart, denyed");
                return LAUNCH_STATE_DENY;
            }
        }

        int autoLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_AUTOLAUNCH.value);
        int secondLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_SECONDARYLAUNCH.value);
        if (((autoLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && !launchByOther)
            || ((secondLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && launchByOther)) {
            if (DEBUG) Slog.d(TAG, "bgclean judgeAppLaunchAllowed: "+targetApp
                + ", callingPackage = "+callerApp+", reason = "+reason +" in my whitelist");
            return LAUNCH_STATE_ALLOW;
        }

        //check whether app is in black list
        boolean bInBlackList = false;
        if ((autoLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && !launchByOther) {
            if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig autolaunch black list: " + targetApp);
            bInBlackList = true;
        }
        if ((secondLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && launchByOther) {
            if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig 2ndlaunch black list: " + targetApp);
            bInBlackList = true;
        }

        // check whether blacklist app is in exception
        if (bInBlackList) {
            // not allow auto start app that in auto start black list
            // 1. in mAutoLaunch_BlackList AND is not launched by other app (that is launched by system broadcast etc)
            // 2. NOTE: Exception:
            //     1) Start reason is REASON_START_ACTIVITY  (this is alway happened in case of
            //         app use another app to do something, including launcher to launch a app)
            //     2) Self start self ( that is this app is alreadby started, and is start some activity internal)
            if (!launchByOther && !REASON_START_ACTIVITY.equals(reason)) {
                if (DEBUG) Slog.d(TAG, "in autolaunch black list: "+targetApp
                    + ", callingPackage = "+callerApp+", reason = "+reason +" denyed!");
                return LAUNCH_STATE_DENY;
            }
            // not allow auto start by other app that in secondary start black list
            // 1. in m2ndLaunch_BlackList AND is launched by other app
            // 2. NOTE: Exception:
            //     1) when callerApp is top AND Start reason is REASON_START_ACTIVITY  (this is alway happened in case of
            //         app use another app to do something, including launcher to launch a app)
            //     2) Self start self ( that is this app is alreadby started, and is start some activity internal)
            //     3) when callerApp is top AND targetApp is in AssociateLaunchExceptionAppList
            if (launchByOther && !launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
                if (DEBUG) Slog.d(TAG, "in 2ndlaunch black list: "+targetApp
                    + ", callingPackage = "+callerApp+", reason = "+ reason + " intent:" + intent + " denyed!");
                return LAUNCH_STATE_DENY;
            }

            // Although it is black list, but it start by user, so allowed to start
            return LAUNCH_STATE_ALLOW;
        }
        return LAUNCH_STATE_AUTO;
    }

BackgroundCleanHelper.java-->checkLaunchStateByUserSetting()

這個方法就是根據使用者的設定,來判斷是否攔截自啟

private int checkLaunchStateByUserSetting(Intent intent, String targetApp, int targetUid,
            String callerApp, int callerUid, String reason) {

        if (targetApp == null || targetApp.equals(callerApp))
            return LAUNCH_STATE_AUTO;

        boolean launchByOther = autoLaunchByOtherApp(targetApp, targetUid, callerApp, callerUid, reason);

        // allow app in whitelist
        if (inSelfStartWhiteAppList(targetApp)) {
            return LAUNCH_STATE_ALLOW;
        }

        // if in ultrasaving mode, don't allow autostart except apps in ultrasve applist
        if (!launchByOther && (PowerManagerEx.MODE_ULTRASAVING == mPowerSaveMode)
            && (PowerManagerEx.MODE_ULTRASAVING == mNextPowerSaveMode)) {
            List<String> appList = mPowerControllerInternal.getAppList_UltraMode();
            if (!appList.contains(targetApp)) {
                if (DEBUG) Slog.d(TAG, "app: " + targetApp + " in applist of ultramode, refuse to autostart, denyed");
                return LAUNCH_STATE_DENY;
            }
        }

        int autoLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_AUTOLAUNCH.value);
        int secondLaunch = mPowerControllerInternal.getAppPowerSaveConfgWithTypeInternal(targetApp,AppPowerSaveConfig.ConfigType.TYPE_SECONDARYLAUNCH.value);
        if (((autoLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && !launchByOther)
            || ((secondLaunch == AppPowerSaveConfig.VALUE_NO_OPTIMIZE) && launchByOther)) {
            if (DEBUG) Slog.d(TAG, "bgclean judgeAppLaunchAllowed: "+targetApp
                + ", callingPackage = "+callerApp+", reason = "+reason +" in my whitelist");
            return LAUNCH_STATE_ALLOW;
        }

        //check whether app is in black list
        boolean bInBlackList = false;
        if ((autoLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && !launchByOther) {
            if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig autolaunch black list: " + targetApp);
            bInBlackList = true;
        }
        if ((secondLaunch == AppPowerSaveConfig.VALUE_OPTIMIZE) && launchByOther) {
            if (DEBUG_MORE) Slog.d(TAG, "in apppowerconfig 2ndlaunch black list: " + targetApp);
            bInBlackList = true;
        }

        // check whether blacklist app is in exception
        if (bInBlackList) {
            // not allow auto start app that in auto start black list
            // 1. in mAutoLaunch_BlackList AND is not launched by other app (that is launched by system broadcast etc)
            // 2. NOTE: Exception:
            //     1) Start reason is REASON_START_ACTIVITY  (this is alway happened in case of
            //         app use another app to do something, including launcher to launch a app)
            //     2) Self start self ( that is this app is alreadby started, and is start some activity internal)
            if (!launchByOther && !REASON_START_ACTIVITY.equals(reason)) {
                if (DEBUG) Slog.d(TAG, "in autolaunch black list: "+targetApp
                    + ", callingPackage = "+callerApp+", reason = "+reason +" denyed!");
                return LAUNCH_STATE_DENY;
            }
            // not allow auto start by other app that in secondary start black list
            // 1. in m2ndLaunch_BlackList AND is launched by other app
            // 2. NOTE: Exception:
            //     1) when callerApp is top AND Start reason is REASON_START_ACTIVITY  (this is alway happened in case of
            //         app use another app to do something, including launcher to launch a app)
            //     2) Self start self ( that is this app is alreadby started, and is start some activity internal)
            //     3) when callerApp is top AND targetApp is in AssociateLaunchExceptionAppList
            if (launchByOther && !launchedByUserActivity(intent, targetApp, targetUid, callerApp, callerUid, reason, true)) {
                if (DEBUG) Slog.d(TAG, "in 2ndlaunch black list: "+targetApp
                    + ", callingPackage = "+callerApp+", reason = "+ reason + " intent:" + intent + " denyed!");
                return LAUNCH_STATE_DENY;
            }

            // Although it is black list, but it start by user, so allowed to start
            return LAUNCH_STATE_ALLOW;
        }
        return LAUNCH_STATE_AUTO;
    }

繼續逐個分析涉及到的主要方法

BackgroundCleanHelper.java-->checkLaunchStateByUserSetting()-->autoLaunchByOtherApp()

    // return true, if app is start by system broadcast
    private boolean autoLaunchByOtherApp(String targetApp, int targetUid,
                String callerApp, int callerUid, String reason) {
        if (callerApp == null
            ||callerApp.equals("android")
            || callerApp.equals("com.android.systemui"))
            return false;

        AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
        if (callerAppState != null && callerAppState.mUid < Process.FIRST_APPLICATION_UID)
            return false;

        return true;
    }

BackgroundCleanHelper.java-->checkLaunchStateByUserSetting()-->launchedByUserActivity()

 private boolean launchedByUserActivity(Intent intent, String targetApp, int targetUid,
            String callerApp, int callerUid, String reason, boolean ignoreTouchTime) {
        boolean userLaunched = false;

        long now = SystemClock.elapsedRealtime();
        long lastTouchTime = 0;
        AppState callerAppState = mAppStateInfoCollector.getAppState(callerApp, UserHandle.getUserId(callerUid));
        if (mPowerControllerInternal != null) {
            lastTouchTime = mPowerControllerInternal.getLastTouchEventTimeStamp();
        }

        boolean isCallerTopApp  =  false;
        if (callerAppState != null
            &&((callerAppState.mProcState == ActivityManager.PROCESS_STATE_TOP)
                || (callerAppState.mProcState == ActivityManager.PROCESS_STATE_HOME)
                || (callerAppState.mState == Event.MOVE_TO_FOREGROUND)
                || (now - callerAppState.mLastTimeUsed) < 1000
                || isLauncherApp(callerApp)) // for Bug#712736
        ) {

            isCallerTopApp = true;
        }

        // check the associated-starting because of third party push service
        if (isCallerTopApp &&
            REASON_START_ACTIVITY.equals(reason)
            && !isLauncherAction(intent)
            && intent != null
            && ThirdpartyPush.isAssociatedComponent(intent.getComponent())) {
            if (DEBUG) Slog.d(TAG,"launchedByUserActivity : Start Proc : "+targetApp
                +", callingPackage = "+callerApp
                + " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
                +"), reason = "+reason
                + " Associated-Starting ThirdParty Push Service");
            isCallerTopApp = false;
        }

        // see the caller of a launcher action as top app
        // add for bug#776461
        if (!isCallerTopApp && intent != null && isLauncherAction(intent)) {
            isCallerTopApp = true;
        }

        if (DEBUG_MORE) {
            Slog.d(TAG,"launchedByUserActivity : Start Proc : "+targetApp
                +", callingPackage = "+callerApp
                + " (ProcState:" + (callerAppState != null ? Util.ProcState2Str(callerAppState.mProcState):"none")
                +"), reason = "+reason);
        }

        long lastTouchElasedTime = now - lastTouchTime;
        if (DEBUG) Slog.d(TAG, "lastTouchElasedTime: "+lastTouchElasedTime);

        if (isCallerTopApp
            && (REASON_START_ACTIVITY.equals(reason)
                    || (!ignoreTouchTime && lastTouchElasedTime <= (1*1000)))
            ) {
            userLaunched = true;
        }

        // check if this call from "android"
        if (!isCallerTopApp && REASON_START_ACTIVITY.equals(reason) && lastTouchElasedTime <= (1*1000)) {
            AppState androidState = mAppStateInfoCollector.getAppState("android", UserHandle.USER_SYSTEM);
            if (androidState != null
                && (androidState.mState == Event.MOVE_TO_FOREGROUND)
                    || (now - androidState.mLastTimeUsed) < 1000) {
                userLaunched = true;
            }
        }

        // Bug#707888 setting monkey fail --> BEG
        // for callerApp is system app, and use "start-activity", then allow
        if ((callerAppState == null || callerAppState.mUid < Process.FIRST_APPLICATION_UID)
            && REASON_START_ACTIVITY.equals(reason)) {
            userLaunched = true;
        }
        // Bug#707888 setting monkey fail <-- END

        return userLaunched;
    }

BackgroundCleanHelper.java-->checkLaunchStateByUserSetting()-->launchedByUserActivity()-->isLauncherApp()

    private boolean isLauncherApp(String pkgName) {
        int index = mLauncherAppList.indexOf(pkgName);
        if (index >= 0) {
            return true;
        }
        return false;
    }

isLauncherApp主要是通過是否有CATEGORY_HOME屬性判斷的


    private void loadLauncherApps() {
        try {

            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_HOME);

            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, "- loadLauncherApps() for user: " + user.id);
                List<ResolveInfo> resolves =
                    mContext.getPackageManager().queryIntentActivitiesAsUser(intent, PackageManager.MATCH_DISABLED_COMPONENTS, user.id);

                // Look for the original activity in the list...
                final int N = resolves != null ? resolves.size() : 0;
                for (int i=0; i<N; i++) {
                    final ResolveInfo candidate = resolves.get(i);
                    final ActivityInfo info = candidate.activityInfo;
                    if (info != null && info.packageName != null
                        && !mLauncherAppList.contains(info.packageName)) {
        ......
            /*check if contains the default launcher*/
            for(String s : mDefaultLauncherAppList) {
                if(!mLauncherAppList.contains(s)) {
                    mLauncherAppList.add(s);
                }
            }
        ......
                        
}
    // default launcher app list
    private String[] mDefaultLauncherAppList = new String[] {
        "com.android.launcher3",
        "com.android.settings"
    };

這一篇就分析到這裡!