Framework基础:点击桌面图标时桌面pause流程

小新

当我们点击桌面的图标时,我们首先会把桌面Launch给pause掉,然后再显示我们启动的应用。

一.流程图

pause流程

1.ActivityManagerService.startActivity

主要包含调用者的信息,调用者就是Laucher。要启动的Activity的信息在intent和startFlags里面。加入了userid后,接下来调用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());
    }

下面时动态调试断点看到的值。


startActivity

2.ActivityManagerService.startActivityAsUser

(1) enforceNotIsolatedCaller函数限制了Isolated process调用startActivity。如果是Isolated process调用startActivity,会抛出SecurityException。
(2)handleIncomingUser校验CallingUid属于userid。对于但用户手机userid==0。
接下来调用ActivityStackSupervisor.startActivityMayWait方法启动Activity。ActivityStackSupervisor是用于管理Activity栈的。全局只有一个ActivityStackSupervisor。一个stack可以包含多个task。栈顶的Activity会显示给用户看。

    @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来获取要启动的应用信息,将应用信息保存到aInfo。
接下来调用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;


        // 获取应用的信息
        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,即调用者Launcher的PID和UID
2.打印启动信息“START u 0 ...”
3.校验要启动的应用信息ainfo和intent。
3.初始化sourceRecord,resultRecord,resultStack,如果启动失败,将通过resultStack告知调用者。当然桌面启动的话,resultRecord和resultStack都是空的。
4.检查action和compont的启动权限。我觉得这个是这个函数主要做的事情。用于校验调用者的权限和组件是否是黑名单。例如一些rom厂商都会配置一些黑名单应用组件。
5.调用startActivityUncheckedLocked进行下一步。
输入的变量信息如下图:


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的启动权限
          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;
        }
        //调用startActivityUncheckedLocked
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);

        return err;
    }

5.ActivityStackSupervisor.startActivityUncheckedLocked

1.startActivityUncheckedLocked主要是根据launchFlags来决定新建还是服用task和stack。桌面启动会新建targetStack和task,把targetStack放在所有stack的最前面(这时没有设置task在targetStack的位置哦,在下一步才设置)。设置要启动的ActivityRecord为focus。
2.找到stack后,接下来调用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,并设置为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);
       //设置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做一些切换的准备动作。最后这个stack的状态搞好了,就调用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();

          //准备做动画
                 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

这个函数比较简单啦,就是找到最top的stack,然后调用stack的resumeTopActivityLocked。在startActivityUncheckedLocked的时候已经通过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

会调用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;
        }
       .....
}

过程总结:
1.ActivityManagerService.startActivity是入口
2.ActivityManagerService.startActivityAsUser是包含user id的入口
3.ActivityStackSupervisor.startActivityMayWait 是AMS管理Activity的入口,主要获取要启动Activity的应用信息aInfo。
4.ActivityStackSupervisor.startActivityLocked主要是检验权限,将要启动的Activity信息包装到ActiviyRecord中。
5.ActivityStackSupervisor.startActivityUncheckedLocked会新建targetStack和task,把targetStack放在所有stack的最前面。
6.ActivityStack.startActivityLocked主要是把task推到stack的top。然后window做一些切换的准备动作。
7.ActivityStackSupervisor.resumeTopActivitiesLocked 找到最top的stack,然后调用stack的resumeTopActivityLocked。

  1. ActivityStack.resumeTopActivityLocked调用mStackSupervisor.pauseBackStacks把非front的Stack都pause掉,桌面这时已经不是front,所以会被pause掉。

现在只说到Launcher pause了,但要启动的Activity还没有resume。下节再来讲述他是怎么resume的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容