Framework基礎(chǔ):點擊桌面圖標(biāo)時桌面pause流程

小新

當(dāng)我們點擊桌面的圖標(biāo)時闪幽,我們首先會把桌面Launch給pause掉啥辨,然后再顯示我們啟動的應(yīng)用。

一.流程圖

pause流程

1.ActivityManagerService.startActivity

主要包含調(diào)用者的信息盯腌,調(diào)用者就是Laucher溉知。要啟動的Activity的信息在intent和startFlags里面。加入了userid后腕够,接下來調(diào)用startActivityAsUser级乍。

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

下面時動態(tài)調(diào)試斷點看到的值。


startActivity

2.ActivityManagerService.startActivityAsUser

(1) enforceNotIsolatedCaller函數(shù)限制了Isolated process調(diào)用startActivity帚湘。如果是Isolated process調(diào)用startActivity玫荣,會拋出SecurityException引有。
(2)handleIncomingUser校驗CallingUid屬于userid却汉。對于但用戶手機userid==0居灯。
接下來調(diào)用ActivityStackSupervisor.startActivityMayWait方法啟動Activity勉耀。ActivityStackSupervisor是用于管理Activity棧的。全局只有一個ActivityStackSupervisor溉苛。一個stack可以包含多個task缩抡。棧頂?shù)腁ctivity會顯示給用戶看歹叮。

    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
        enforceNotIsolatedCaller("startActivity");
        userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
                false, ALLOW_FULL_ONLY, "startActivity", null);
        // TODO: Switch to user app stacks here.
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }

3. ActivityStackSupervisor.startActivityMayWait

(1)通過resolveActivity來獲取要啟動的應(yīng)用信息贿堰,將應(yīng)用信息保存到aInfo辙芍。
接下來調(diào)用startActivityLocked。
輸入的變量信息如下圖:


startActivityMayWait

    final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
            Bundle options, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {

        boolean componentSpecified = intent.getComponent() != null;


        // 獲取應(yīng)用的信息
        ActivityInfo aInfo =
                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);

        synchronized (mService) {
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);
         }
    }
 

4. ActivityStackSupervisor.startActivityLocked

1.初始化了callingPid和callingUid羹与,即調(diào)用者Launcher的PID和UID
2.打印啟動信息“START u 0 ...”
3.校驗要啟動的應(yīng)用信息ainfo和intent故硅。
3.初始化sourceRecord,resultRecord注簿,resultStack契吉,如果啟動失敗,將通過resultStack告知調(diào)用者诡渴。當(dāng)然桌面啟動的話,resultRecord和resultStack都是空的菲语。
4.檢查action和compont的啟動權(quán)限妄辩。我覺得這個是這個函數(shù)主要做的事情。用于校驗調(diào)用者的權(quán)限和組件是否是黑名單山上。例如一些rom廠商都會配置一些黑名單應(yīng)用組件眼耀。
5.調(diào)用startActivityUncheckedLocked進(jìn)行下一步。
輸入的變量信息如下圖:


startActivityUncheckedLocked

   final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            ActivityContainer container, TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;
        //初始化callingpid和callinguid
        ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                      + " (pid=" + callingPid + ") when starting: "
                      + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
         //打印啟動log
        if (err == ActivityManager.START_SUCCESS) {
            Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
                    + "} from uid " + callingUid
                    + " on display " + (container == null ? (mFocusedStack == null ?
                            Display.DEFAULT_DISPLAY : mFocusedStack.mDisplayId) :
                            (container.mActivityDisplay == null ? Display.DEFAULT_DISPLAY :
                                    container.mActivityDisplay.mDisplayId)));
        }
        //初始化sourceRecord和resultRecord
        ActivityRecord sourceRecord = null;
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            sourceRecord = isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }
        //檢驗intent和ainfo信息
        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
            // We couldn't find a class that can handle the given Intent.
            // That's the end of that!
            err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }

        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
            // We couldn't find the specific class specified in the Intent.
            // Also the end of the line.
            err = ActivityManager.START_CLASS_NOT_FOUND;
        }

        if (err == ActivityManager.START_SUCCESS
                && !isCurrentProfileLocked(userId)
                && (aInfo.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) {
            // Trying to launch a background activity that doesn't show for all users.
            err = ActivityManager.START_NOT_CURRENT_USER_ACTIVITY;
        }
          //檢查action和compont的啟動權(quán)限
          boolean abort = false;
        
        final int startAnyPerm = mService.checkPermission(
                START_ANY_ACTIVITY, callingPid, callingUid);

        if (startAnyPerm != PERMISSION_GRANTED) {
            final int componentRestriction = getComponentRestrictionForCallingPackage(
                    aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
            final int actionRestriction = getActionRestrictionForCallingPackage(
                    intent.getAction(), callingPackage, callingPid, callingUid);

            if (componentRestriction == ACTIVITY_RESTRICTION_PERMISSION
                    || actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
                if (resultRecord != null) {
                    resultStack.sendActivityResultLocked(-1,
                            resultRecord, resultWho, requestCode,
                            Activity.RESULT_CANCELED, null);
                }
                String msg;
                if (actionRestriction == ACTIVITY_RESTRICTION_PERMISSION) {
                    msg = "Permission Denial: starting " + intent.toString()
                            + " from " + callerApp + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")" + " with revoked permission "
                            + ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction());
                } else if (!aInfo.exported) {
                    msg = "Permission Denial: starting " + intent.toString()
                            + " from " + callerApp + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " not exported from uid " + aInfo.applicationInfo.uid;
                } else {
                    msg = "Permission Denial: starting " + intent.toString()
                            + " from " + callerApp + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " requires " + aInfo.permission;
                }
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }

            if (actionRestriction == ACTIVITY_RESTRICTION_APPOP) {
                String message = "Appop Denial: starting " + intent.toString()
                        + " from " + callerApp + " (pid=" + callingPid
                        + ", uid=" + callingUid + ")"
                        + " requires " + AppOpsManager.permissionToOp(
                                ACTION_TO_RUNTIME_PERMISSION.get(intent.getAction()));
                Slog.w(TAG, message);
                abort = true;
            } else if (componentRestriction == ACTIVITY_RESTRICTION_APPOP) {
                String message = "Appop Denial: starting " + intent.toString()
                        + " from " + callerApp + " (pid=" + callingPid
                        + ", uid=" + callingUid + ")"
                        + " requires appop " + AppOpsManager.permissionToOp(aInfo.permission);
                Slog.w(TAG, message);
                abort = true;
            }
        }

        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);

        if (mService.mController != null) {
            try {
                // The Intent we give to the watcher has the extra data
                // stripped off, since it can contain private information.
                Intent watchIntent = intent.cloneFilter();
                abort |= !mService.mController.activityStarting(watchIntent,
                        aInfo.applicationInfo.packageName);
            } catch (RemoteException e) {
                mService.mController = null;
            }
        }
         //初始化啟動的ActivityRecord
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);
        if (outActivity != null) {
            outActivity[0] = r;
        }
        //調(diào)用startActivityUncheckedLocked
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);

        return err;
    }

5.ActivityStackSupervisor.startActivityUncheckedLocked

1.startActivityUncheckedLocked主要是根據(jù)launchFlags來決定新建還是服用task和stack佩憾。桌面啟動會新建targetStack和task哮伟,把targetStack放在所有stack的最前面(這時沒有設(shè)置task在targetStack的位置哦干花,在下一步才設(shè)置)。設(shè)置要啟動的ActivityRecord為focus楞黄。
2.找到stack后池凄,接下來調(diào)用ActivityStack的startActivityLocked方法來啟動。


startActivityUncheckedLocked

    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
        //獲取啟動flag
        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

        int launchFlags = intent.getFlags();
        //選擇stack和新建task
        // Should this be considered a new task?
        if (r.resultTo == null && inTask == null && !addingToTask
                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            targetStack = computeStackFocus(r, newTask);
             //把stack推到最前面
            targetStack.moveToFront("startingNewTask");
            //新建task鬼廓,并設(shè)置為ActivityRecord的task
            if (reuseTask == null) {
              r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                        newTaskInfo != null ? newTaskInfo : r.info,
                        newTaskIntent != null ? newTaskIntent : intent,
                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                        taskToAffiliate);
                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                        "Starting new activity " + r + " in new task " + r.task);
            } else {
                r.setTask(reuseTask, taskToAffiliate);
            }
        } 

        targetStack.mLastPausedActivity = null;
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
       //設(shè)置focus ActivityRecord
        if (!launchTaskBehind) {
            // Don't set focus on an activity that's going to the back.
            mService.setFocusedActivityLocked(r, "startedActivity");
        }
        return ActivityManager.START_SUCCESS;
    }

6.ActivityStack.startActivityLocked

主要是把task推到stack的top肿仑。然后window做一些切換的準(zhǔn)備動作。最后這個stack的狀態(tài)搞好了碎税,就調(diào)用mStackSupervisor.resumeTopActivitiesLocked來resume所有top的Activities尤慰。


startActivityLocked
   final void startActivityLocked(ActivityRecord r, boolean newTask,
           boolean doResume, boolean keepCurTransition, Bundle options) {
       TaskRecord rTask = r.task;
       final int taskId = rTask.taskId;
      //把task放到stack的top位置
       insertTaskAtTop(rTask, r);
       mWindowManager.moveTaskToTop(taskId);
       }
       TaskRecord task = null;
       task = r.task;

       //把ActivityRecord放在task的top,并且放到History中
       task.addActivityToTop(r);
       task.setFrontOfTask();

       r.putInHistory();

          //準(zhǔn)備做動畫
                 mWindowManager.prepareAppTransition(newTask
                       ? r.mLaunchTaskBehind
                               ? AppTransition.TRANSIT_TASK_OPEN_BEHIND
                               : AppTransition.TRANSIT_TASK_OPEN
                       : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
               mNoAnimActivities.remove(r);


       if (doResume) {
           mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
       }
   }

7.ActivityStackSupervisor.resumeTopActivitiesLocked

這個函數(shù)比較簡單啦雷蹂,就是找到最top的stack伟端,然后調(diào)用stack的resumeTopActivityLocked。在startActivityUncheckedLocked的時候已經(jīng)通過targetStack.moveToFront把這個targetStack搞定最前面了匪煌。

   boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = mFocusedStack;
        }
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }

        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (stack == targetStack) {
                    // Already started above.
                    continue;
                }
                if (isFrontStack(stack)) {
                    stack.resumeTopActivityLocked(null);
                }
            }
        }
        return result;
    }

8. ActivityStack.resumeTopActivityLocked

會調(diào)用mStackSupervisor.pauseBackStacks把桌面pause掉责蝠。
桌面pause掉之后會告知AMS,AMS重新走ActivityStackSupervisor.resumeTopActivitiesLocked來拉起TOP的activity虐杯。

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
        ......
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        if (pausing) {
            if (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
                    "resumeTopActivityLocked: Skip resume: need to start pausing");
            // At this point we want to put the upcoming activity's process
            // at the top of the LRU list, since we know we will be needing it
            // very soon and it would be a waste to let it get killed if it
            // happens to be sitting towards the end.
            if (next.app != null && next.app.thread != null) {
                mService.updateLruProcessLocked(next.app, true, null);
            }
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            return true;
        }
       .....
}

過程總結(jié):
1.ActivityManagerService.startActivity是入口
2.ActivityManagerService.startActivityAsUser是包含user id的入口
3.ActivityStackSupervisor.startActivityMayWait 是AMS管理Activity的入口玛歌,主要獲取要啟動Activity的應(yīng)用信息aInfo。
4.ActivityStackSupervisor.startActivityLocked主要是檢驗權(quán)限擎椰,將要啟動的Activity信息包裝到ActiviyRecord中支子。
5.ActivityStackSupervisor.startActivityUncheckedLocked會新建targetStack和task,把targetStack放在所有stack的最前面达舒。
6.ActivityStack.startActivityLocked主要是把task推到stack的top值朋。然后window做一些切換的準(zhǔn)備動作。
7.ActivityStackSupervisor.resumeTopActivitiesLocked 找到最top的stack巩搏,然后調(diào)用stack的resumeTopActivityLocked昨登。

  1. ActivityStack.resumeTopActivityLocked調(diào)用mStackSupervisor.pauseBackStacks把非front的Stack都pause掉,桌面這時已經(jīng)不是front贯底,所以會被pause掉丰辣。

現(xiàn)在只說到Launcher pause了,但要啟動的Activity還沒有resume禽捆。下節(jié)再來講述他是怎么resume的笙什。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市胚想,隨后出現(xiàn)的幾起案子琐凭,更是在濱河造成了極大的恐慌,老刑警劉巖浊服,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件统屈,死亡現(xiàn)場離奇詭異胚吁,居然都是意外死亡,警方通過查閱死者的電腦和手機愁憔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門腕扶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惩淳,你說我怎么就攤上這事蕉毯。” “怎么了思犁?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵代虾,是天一觀的道長。 經(jīng)常有香客問我激蹲,道長棉磨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任学辱,我火速辦了婚禮乘瓤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘策泣。我一直安慰自己衙傀,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布萨咕。 她就那樣靜靜地躺著统抬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪危队。 梳的紋絲不亂的頭發(fā)上聪建,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音茫陆,去河邊找鬼金麸。 笑死,一個胖子當(dāng)著我的面吹牛簿盅,可吹牛的內(nèi)容都是我干的挥下。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼桨醋,長吁一口氣:“原來是場噩夢啊……” “哼见秽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讨盒,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎步责,沒想到半個月后返顺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體禀苦,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年遂鹊,在試婚紗的時候發(fā)現(xiàn)自己被綠了振乏。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡秉扑,死狀恐怖慧邮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舟陆,我是刑警寧澤误澳,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站秦躯,受9級特大地震影響忆谓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踱承,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一倡缠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧茎活,春花似錦昙沦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至身辨,卻和暖如春丐谋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背煌珊。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工号俐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人定庵。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓吏饿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蔬浙。 傳聞我的和親對象是個殘疾皇子猪落,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容