AMS分析「 Activity启动流程 」

Activity是Android应用程序的四大组件之一,负责管理Android应用程序的用户界面,一般一个应用程序中包含很多个Activity,他们可能运行在一个进程中,也可能运行在不同的进程中。

我们主要通过启动在不同进程中的Activity,来分析Activity的启动流程及AMS对Activity的管理逻辑。

Activity启动.png

有两个应用程序App1和App2,在App1的Activity A中点击button 启动 App2中的Activity B。
通过分析以上ActivityB的启动过程来了解AMS对Activity的管理逻辑。


image.png

步骤1:Activity A告诉AMS服务准备启动Activity B

步骤2:AMS服务处理并通知Activity A所在的进程pause Activity A,Activity A所在的进程处理完成之后,通知AMS服务Activity A已经完成pause工作。

步骤3:Activity B所在的进程没有启动,AMS服务首先启动一个新的进程。新的进程启动完成之后,通知AMS服务进程启动完成。

步骤4:AMS服务通知新的进程来启动Activity B,新的进程启动Activity B完成之后,通知AMS服务Activity B启动完成。

在分析Activity启动流程之前我们先简单介绍下应用进程和AMS服务通信方法,AMS服务和应用进程间属于不同的进程,两者之间通信肯定和Binder有关。我们知道系统的服务都是实现了Binder的服务端,应用进程要想和它通信需要获取它的代理端。

然而AMS服务是如何和应用进程通信的呢?在创建一个新的应用进程之后,系统首先会启动ActivityThread,ActivityThread是应用进程的主线程,在ActivityThread创建的时候会创建一个ApplicationThread的对象。这个ApplicationThread实现了一个Binder的服务端。新的进程创建完成之后通知AMS服务的之后同时把自己进程的ApplicationThread的代理端送给AMS服务。AMS服务中保存了所有应用进程的ApplicationThread的代理对象。所以AMS要想给应用进程发送消息,只需要得到目标应景进程的ApplicationThread的代理端对象即可。

由于Activity的启动流程比较复杂,一步一步来分析,这样比较容易理解。

第一步:准备启动

1. Activity.startActivity

在activity A中点击button启动activity B调用了 Activity的startActivity方法。

public void startActivity(Intent intent, @Nullable Bundle options) {        
        if (options != null) {
            startActivityForResult(intent, -1, options);        
        ……    }

在该方法中调用了activity的startActivityForResult方法来启动Intent描述的Activity B,第二个参数-1表示不需要返回结果

2. Activity. startActivityForResult

public void startActivityForResult(
            String who, Intent intent, int requestCode, @Nullable Bundle options) {           
                Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, who, intent, requestCode, options);
       ……    
}

在这个方法中最终调用了Instrumentation的execStartActivity方法来启动Activity。应用程序和系统之间的交互都集中交给Instrumentation来做,方便系统对这些活动的监视。

下面我们看下参数mMainThread.getApplicationThread(),mMainThread就是应用app1所在进程的主线程ActivityThread,getApplicationThread返回的是一个ActivityThread的内部类ApplicationThread,该类是一个Binder对象,实现了Binder的服务端,通过参数传入到AMS服务中,AMS服务中则会保存它的客户端,这样AMS就可以通过它和应用进程通信了。

参数mToken是一个Binder代理对象,它指向了AMS中一个保存的ActivityRecord信息,mToken代表了Activity A,它通过参数传递给AMS后,AMS根据它就可以得到Activity A的信息了。

3. Instrumentation. execStartActivity

public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
       
        try {
            //intent做进程间传输的准备工作
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            //进程间传输,最终调用到AMS服务中
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        }
      ……
    }

该方法中通过ActivityManagerNative的getDefault方法来获得AMS的代理对象,然后调用它的startActivity方法通过进程间传输调用到AMS服务startActivity方法,进程间的通信此处不再详细介绍。
到此处为止,以上的操作都是在应用程序App1的进程中执行的。以下代码就进入了SystemServer进程的AMS服务中

4. AMS.startActivity

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

该方法的参数中caller就是App1进程的ApplicationThread的binder对象,IBinder就是指向Activity A的ActivityRecord的Binder对象,紧接着这个方法就调用了startActivityAsUser方法

5. AMS. startActivityAsUser

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) {
       ……
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, false, userId, null, null);
    }

调用了activityStackSupervisor的startActivityMayWait方法,ActivityStackSupervisor是Activity调度的核心类,Activity的调度相关的工作都是在ActivityStackSuperVisor中处理,主要管理Task和Stack.它是在AMS启动的时候创建的。

6. 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) {
        ……
        //PMS服务根据intent查询要启动的Activity B的信息,保存到ActivityInfo中
        intent = new Intent(intent);
        ActivityInfo aInfo =
                resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);
            ……
            
            //决定当前活动的stack
ActivityContainer container = (ActivityContainer)iContainer;
            final ActivityStack stack;
            if (container == null || container.mStack.isOnHomeDisplay()) {
                stack = mFocusedStack;
            } else {
                stack = container.mStack;
            }
 
 
           ……
            //将PMS中查询到的Activity B的信息当做参数
            int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity,
                    componentSpecified, null, container, inTask);
 
          ……
    }

resolveActivity方法中最终是PMS服务根据Intent信息去查询即将要启动的ActivityB的详细信息,然后是查找对应的ActivityStack,即将要启动的Activity应该在放到哪个ActivityStack中,从参数传递过来的iContainer为null,所以要启动的Activity应该在mFocusStack中来管理。mFocusStack指的是当前获得焦点的ActivityStack。

Android中一般情况下有以下几种ActivityStack

1:Home Stack,这个是Launcher所在的Stack。 其实还有一些系统界面也运行在这个Stack上,例如近期任务.SystemUI等
2:FullScreen Stack,全屏的Activity所在的Stack。 但其实在分屏模式下,Id为1的Stack只占了半个屏幕。
3:Freeform模式的Activity所在Stack
4:Docked Stack 下文中我们将看到,在分屏模式下,屏幕有一半运行了一个固定的应用,这个就是这里的Docked Stack
5:Pinned Stack 这个是画中画Activity所在的Stack

第一个和第二个是较常用的Stack,后边三个的Stack主要和多窗口模式有关。由此可见,大部分应用程序其实都是在同一个Stack中即FullScreenStack中。然后调用startActivityLocked方法继续启动Activity.

7. startActivityLocked

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) {
       
        //callerApp 代表调用方的应用进程,即App1的应用进程
        ProcessRecord callerApp = null;
        if (caller != null) {
            //根据caller找到AMS中保存的App1的processRecord对象
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                //得到App1应用进程的pid和应用的uid
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            }
            ……
        }
 
        ……
        //即调用者的Activity组件
        ActivityRecord sourceRecord = null;
        //返回结果的Activity组件
        ActivityRecord resultRecord = null;
        if (resultTo != null) {
            //根据resultTo Binder对象得到其指向的ActivityRecord,即Activity A的ActivityRecord信息
            sourceRecord = isInAnyStackLocked(resultTo);
            //一般情况下请求的Activity和要接收返回结果的Activity是同一个
            if (sourceRecord != null) {
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }
 
        final int launchFlags = intent.getFlags();
 
        ……
        
        //根据准备的信息,创建一个即将启动的ActivityRecord对象,即Activity B
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, this, container, options);
 
        ……
        //将刚创建的目标Activity的ActivityRecord作为参数,继续调用startActivityUncheckedLocked方法来启动
        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
                startFlags, true, options, inTask);
 
        ……
        return err;
    }

StartActivityLocked方法主要作用是创建一个即将要启动的Activity的ActivityRecord对象。该方法中首先根据参数传进来的代表Activity A的binder对象,来获得Activity A的ActivityRecord信息。然后获取调用进程的pid和调用程序的uid。
根据这些信息和ainfo创建一个ActivityRecord对象r,代表ActivityB。这样就获取了调用者的Activity A的组件信息,和即将要启动的目标Activity B的信息。分别保存在sourceRecord和r中,最后调用startActivityUncheckedLocked方法来继续启动Activity B

8. startActivityUncheckedLocked

final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
        
        //根据flag获取相应的启动模式,我们代码中没有设置启动模式,所以默认应该是标准模式,这三个变量都应该是false      
        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;
        ……
        //即将要启动activity的 task
        ActivityStack targetStack;
        ……
        //是否新建一个Task
        boolean newTask = false;
        ……
        //获取Activity A的Task,然后赋值给B,即两个Activity位于同一个Task中
         else if (sourceRecord != null) {
//获取Activity A所在的Task
            final TaskRecord sourceTask = sourceRecord.task;
            //将A所在的ActivityStack作为B启动的Stack
            targetStack = sourceTask.stack;
            targetStack.moveToFront("sourceStackToFront");
            //获取ActivityStack中的 top Task是不是和当前的Task一致,如果不一致则将当前的Task移动到ActivityStack的顶端
            final TaskRecord topTask = targetStack.topTask();
            if (topTask != sourceTask) {
                targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
                        r.appTimeTracker, "sourceTaskToFront");
            }           
        ……
        //将当前Activity Stack mLastPausedActivity设置为null
        targetStack.mLastPausedActivity = null;
        //调用startActivityLocked方法
        targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);

这个方法中主要处理的工作就是Activity四种启动模式的处理。根据Intent中的flag标志来决定不同的启动模式,然后根据不同的启动模式来决定Activity在Task中的位置。这个方法比较复杂,我们只关注了和我们逻辑相关的代码。关于启动模式的处理就不在详细分析。

由于我们没有设置Activity B 的启动模式,即Activity B默认是标准的启动模式。Activity A和Activity B应该放在同一个Task中。

在前面我们也已经分析过了,一般情况下所有的应用程序的Activity都是位于同一个ActivityStack中的。此处代码中也可以分析出把ActivityA所在的ActivityStack直接当成启动Activity B的Activity Stack.

我们通过一幅图来了解下Task和ActivityStack的关系。

Task和Stack

Task和Stack的关系

Android系统中的每一个Activity都位于一个Task中。一个Task可以包含多个Activity,同一个Activity也可 能有多个实例。 在AndroidManifest.xml中,我们可以通过 android:launchMode 来控制Activity在Task中的实例。

另外,在startActivity的时候,我们也可以通过 setFlag 来控制启动的Activity在Task中的实例。

Task管理的意义还在于近期任务列表以及Back栈。 当你通过多任务键(有些设备上是长按Home键,有些设备上是专门提供的多任务键)调出多任务时,其实就是从ActivityManagerService获取了最近启动的Task列表。

其实在ActivityManagerService与WindowManagerService内部管理中,在Task之外,还有一层容器, 这个容器应用开发者和用户可能都不会感觉到或者用到,但它却非常重要,那就是Stack,Android系统中的多窗口管理,就是建立在Stack的数据结构上的 。 一个Stack中包含了多个Task,一个Task中包含了多个Activity(Window)

最后调用获取的ActivityTask的startActivityLocked来继续启动

9. ActivityStack . startActivityLocked

final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
            //获取要启动的Task对象
        TaskRecord rTask = r.task;
        final int taskId = rTask.taskId;
        
         TaskRecord task = null;
        if (!newTask) {
            //遍历当前stack中所有的Task,找到目标task,然后将即将要启动的Activity加入到Task的栈顶
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // All activities in task are finishing.
                    continue;
                }
                if (task == r.task) {
                    
                    if (!startIt) {
                        task.addActivityToTop(r);
                        r.putInHistory();
                        ……
        //传入的resume位 true,然后调用  resumeTopActivitiesLocked方法继续启动Activity         
        if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }

该方法主要作用是变量所有Task,找到目标task然后将即将要启动的Activity的ActivityRecord加入到栈顶

10. ActivityStackSuperVisor. resumeTopActivitiesLocked

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        
        //如果目标stack是front Stack, 则调用resumeTopActivityLocked
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        //否则遍历找到frontStack,执行resumeTopActivityLocked
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ……
                }
                if (isFrontStack(stack)) {
                    stack.resumeTopActivityLocked(null);
                }
    ……

这个方法的主要作用就是找到frontStack然后调用它的resumeTopActivityLocked方法。

由于我们的ActivityA启动ActivityB都是位于同一个stack,所以当前stack就是frontStack,所以直接调用ActicityStack的resumeTopActivityLocked方法。resumeTopActivityLocked方法则直接有调用了resumeTopActivityInnerLocked方法

11. ActivityStack. resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
 
        ……
        //找到栈顶第一个不是出于finishing状态的ActicityRecord
        final ActivityRecord next = topRunningActivityLocked(null);
        ……
        //调用startPausingLocked方法来暂停上一个Activity
         if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }

只看这个方法中的关键部分。首先调用topRunningActivityLocked方法来找到当前栈顶不是出于fininshing状态的ActicityRecord。我们刚才把即将要启动的ActicityRecord r加入到了当前Task的栈顶,所以这个next就是即将要启动的Acticity B的ActicityRecord

当mResumedActivity不是Null的时候就调用startPausingLocked方法来暂停上一个Activity。ActivityStack有三个成员变量,mResumedActivity表示这个栈中处于激活状态的Activity。这个栈中处于激活状态的Acticity就是Acticity A了。mLastPausedActivity表示上一次被暂停的Activity,mLastPausingActivity即当前栈中正在被暂停的Activity.

mResumedActivity表示Activity A不是Null,所以调用startPasingLocked来暂停Activity A。

Activity启动流程的第一部分就到此为止。总结下这部分做的主要工作

  1. 调用Activity的startActivity方法来启动目标Activity
  2. 调用Instrumentation的方法execStartActivity方法,方便Instrumentation对交互进行监测
  3. 以上部分是在App1的进程中执行,之后会通过进程间通信调用到AMS服务中调用AMS的startActivity方法。此时进入SystemServer进程。
  4. 然后由AMS中管理Acticity核心调度的类ActivityStackSupervisor的方法startActivityMayWait来处理。该方法中主要是根据Intent从PMS中查询目标Activity的信息
  5. ActivityStackSuperVisor的startActivityLocked方法主要是在AMS中找调用进程的processRecord信息,调用Activity的ActivityRecord信息,目标Activity还没有启动,所以需要先创建一个目标Activity的ActivityRecord信息。
  6. ActivityStackSuperVisor的StartActivityUncheckedLocked方法主要来处理启动模式相关的逻辑,根据不同的启动模式,找到相应的对的Task,然后又相应的Task进行处理
  7. ActivityStack将目标Activity加入到对应的Task顶部
  8. 调用ActivityStackSuperVisor的resumeTopActivityLocked方法找到处于前台的Stack,然后调用它的resumeTopActivityLocked方法激活目标Activity.
  9. 当前的Stack的栈开始Pasuing调用的Activity
Activity启动流程第一部分

以上几个步骤完成了AMS对调用Activity及目标Activity的信息收集处理,根据启动模式来决定将目标Activity方法那个栈中,然后目标栈开始讲当前处于激活状态的Activity Pause掉给目标Activity腾地方。

接着看第二部分,如何调用Activity 的由Resume变为Pause的过程

第二步:暂停Activity A

12. ActivityStack.startPausingLocked

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        //mResumeActivity代表当前激活的Activity,即Activity A
    ActivityRecord prev = mResumedActivity;
    ……
        //当前处于激活状态mResumedActivity 的设置为null
    mResumedActivity = null;
        //即将要处于pasuing状态的Activity 就是Activity A
        mPausingActivity = prev;
        mLastPausedActivity = prev;
    ……
        //将Activity A的状态设置为PAUSING
        prev.state = ActivityState.PAUSING;
        //找到当前的栈顶的topActivity就是 Activity B 
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
         //调用进程不为null,且调用进程的ApplicationThread不为null
     if (prev.app != null && prev.app.thread != null) {
            try {
               ……
                通过调用进程的ApplicationThread通知调用进程schedulePauseActivity方法
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);

首先得到要Pause的Activity prev,就是mResumeActivity,代表当前处于激活状态的Activity A,然后把mResumeActivity设置为null,因为Activity A马上要为pause状态了,而Activity B还没有启动,所以此时没有激活状态的Activity。

把mPausingActivity设置为Activity B,表示处于Pausing状态的Activity. 同时prev.state = ActivityState.PAUSING,把Activity A的状态设置为PAUSING。

Prev是Activity A的ActivityRecord 对象,prev.app代表的是Activity A所在进程的ProcessRecord,prev.app.thread就是Activity A 所在进程的ApplicationThread,我们在前面说过,ApplicationThread是一个Binder对象,服务端在应用进程中,AMS服务中这持有每个进程的Binder客户端,这样AMS就可以向应用进程发送消息了。

进程间通信Binder机制此处不解释

此方法最后会通过进程间通信调用Activity A所在进程的schedulePauseActivity方法,继续Activity Pause的过程。

13. ApplicationThread. schedulePauseActivity

public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0) | (dontReport ? 2 : 0),
                    configChanges);
        }

应用进程的ApplicationThread是ActivityThread的一个内部类,参数token是一个Binder类型的对象,指向了AMS中与Activity A对应的一个ActivityRecord。当前要进入pause状态,传进来的finished位false。

此方法发送了一个PAUSE_ACTIVITY的Message给Handler,接着看Handler的handleMessage方法

14. H.handleMessage

ase PAUSE_ACTIVITY:
 
            ……
 
            handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,
 
                            (msg.arg1&2) != 0);

调用handlePauseActivity方法来处理

15. ActivityThread.handPauseActivity

private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        ActivityClientRecord r = mActivities.get(token);
        if (r != null) {
            
            //调用Activity A的onPause方法
            performPauseActivity(token, finished, r.isPreHoneycomb());
 
            //等待pause状态的数据写入完成.
            if (r.isPreHoneycomb()) {
                QueuedWork.waitToFinish();
            }
 
             ……
                try {
                    //进程间通信,调用AMS的ActivityPause方法
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {

在ActivityThread中的mActivities集合中保存了当前进程中的所有的Activity,每个Activity都用一个ActivityClientRecord表示,集合中以binder为key来保存,同样AMS服务中的所有Activity也是在一个集合中存储,在AMS服务中的每一个Activity用ActivityRecord来表示,同样key值也是Binder对象,我们知道Binder对象是可以进程间传递的,所以使用binder来做key值,可以使应用进程的ActivityClientRecord和AMS中的ActivityRecord一一对应起来。

此方法中首先根据AMS中传递过了的binder对象来获取应用进程中的ActivityClientRecord对象,由于参数token指向的是AMS中的代表Activity A的ActivityRecord,所以此处获取的就是Activity A的ActivityClientRecord.

然后调用preformPauseActivity方法,这个方法中会调用Activity A的onSaveInstance方法,然后调用Activity A的onPause方法。

因为onSaveInstance方法会存储当前的Activity信息,要写入磁盘进行IO操作,所以QueuedWork.waitToFinish()方法用来等待存储操作完成。

最后,又是进程间通信,调用AMS的activityPaused方法,此处离开了Activity A的进程,进入了AMS的 SystemServer进程。

16. AMS.activityPaused

public final void activityPaused(IBinder token) {
            //获或Activity 所在的ActivityStack
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                //调用目标ActivityStack的activityPauseLocked方法
                stack.activityPausedLocked(token, false);
            }
        }

Token代表的是Activity A ,此处根据token找到Activity A所在的ActivityStack,然后由目标Stack来处理activityPause逻辑

17. ActivityStack.activityPauseLocked

final void activityPausedLocked(IBinder token, boolean timeout) {
        //根据token获取Activity A的ActivityRecord对象
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            //移除pause超时消息
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            if (mPausingActivity == r) {
               //调用completePauseLocked方法继续执行pause逻辑
                completePauseLocked(true);
            } 
    ……

Token代表的是Activity的binder对象,根据token可以获得Activity A的信息ActivityRecord,移除Pause超时消息,当执行完pause逻辑的ActivityRecord和我们执行pause逻辑前的activityRecord一样的时候,即是同一个Activity,就可以调用completePauseLocked方法来完成Activity A Pause最后的逻辑了。

18. ActivityStack. completePauseLocked

if (resumeNext) {
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();
            if (!mService.isSleepingOrShuttingDown()) {
                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
            } 
            ……
        }

resumeNext就是completePauseLocked传进来的参数,为true。调用mStackSupervisor的getFocusedStack()方法来获取正在处理的ActivityStack. mService.isSleepingOrShuttingDown,判断AMS服务是否处于正常激活状态,然后调用mStackSupervisor的resumeTopActivitiesLocked继续处理。

19. ActivityStackSuperVisor. resumeTopActivitiesLocked

这个步骤我们在第10步骤的时候处理过,此处和第10步逻辑一致,如果当前的ActivityStack是frontStack,直接调用ActivityStack的resumeTopActivityLocked。

ActivityStack的resumeTopActivityLocked方法则直接有调用了ActivityStack的resumeTopActivityInnerLocked方法。

20. ActivityStack. resumeTopActivityInnerLocked

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
   ……
        //找到栈顶的Activity,此时栈顶的acitvity就是即将要启动的Activity B
        final ActivityRecord next = topRunningActivityLocked(null);
        ……
        
        //我们知道,在前面Activity A变为pause状态的时候,我们就把mResumeActivity 置为了Null
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
        }
        ……
        //即将要启动的Activity处于一个新的进程,目前还没有启动
        if (next.app != null && next.app.thread != null) {
            ……
        }else{
            ……
            //来启动目标Activity
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

在第11步的时候,已经走过这个方法的逻辑,那个时候调用这个方法来激活目标Activity的时候,判断mResumeActivity不为空,说明当前有一个处于正在激活状态的Activity,需要先将原先的Activity变为pause状态。

当Activity A变为Pause状态后,再次走到这个方法来激活目标Activity,此时mResumeActivity已经为空,所以不需要再执行pause的逻辑。

然后判断目标Activity next的进程app和ApplicationThread是否为空,因为Activity A 所在的进程还没有创建,所以两个都为空,直接执行mStackSupervisor的startSpecificActivityLocked来启动新的Activity。


Activity启动第二部分

第三步:启动新进程

21. ActivityStackSuperVisor. startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //获取目标Activity的进程ProcessRecord
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        ……
        //,由于目标Activity所在进程还没有创建,所以为空
        if (app != null && app.thread != null) {
           ……
 
        }
        //
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

该方法比较简单,根据目标Activity的ProcessName来查找对应的ProcessRecord.根据processRecord中的进程app和ApplicationThread来判断,如果这两个变量不为空,说明目标Activity的进程和运行环境已经具备,直接启动Activity就可以,我们知道目前目标Activity的进程还没有启动,所以需要调用AMS先启动一个目标Activity的进程。

22. AMS. startProcessLocked

final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
            ……) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
         if (!isolated) {
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            
             String hostingNameStr = hostingName != null
                ? hostingName.flattenToShortString() : null;
        
        ……
        startProcessLocked(
            app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);

得到一个processRecord对象,然后把目标activity的Compoment转化成一个字符串,方便传输。最后调用另一个startProcessLocked方法来继续处理新进程的启动。

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
            
            int uid = app.uid;
            int[] gids = null;
            ……
             //從PMS服务中查找目标应用对应的权限组
             final IPackageManager pm = AppGlobals.getPackageManager();
                    permGids = pm.getPackageGids(app.info.packageName, app.userId);
                    ……
                    gids = new int[permGids.length + 2];
                    System.arraycopy(permGids, 0, gids, 2, permGids.length);
             ……
             app.gids = gids;
             
             ……
              if (entryPoint == null) entryPoint = "android.app.ActivityThread";
             调用Process的静态方法启动一个新的进程 
             Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);

这个方法做的主要工作就是调用Process的静态方法启动一个新的进程,启动新的进程的过程大概是,Zygote进程会fork一个新的子进程出来,子进程创建完成之后,classLoader加载ActivityThread类并创建一个ActivityThread实例,反射调用ActivityThread的main方法。这样ActivityThread主线程就在新的进程中启动起来了。

接着看ActivityThread的main方法,此时已经在新的进程中执行了。我们来看ActivityThread的main方法。

23. ActivityThread.main

public static void main(String[] args) {
       
        Looper.prepareMainLooper();
 
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
 
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        
        Looper.loop();
}

这个方法主要工作就是调用Looper.prepareMainLooper创建一个消息循环队列,然后调用Looper.loop进入消息循环,当前线程进入消息循环中,使当前线程成为新进程的主线程,然后创建一个ActivityThread对象,调用Attach方法。

24. ActivityThread.attach

final ApplicationThread mAppThread = new ApplicationThread();
 
private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            ……
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
            ……
        } else {
        } 

在AMS服务启动的时候,初始系统进程的运行环境的时候,那时候传入的参数system为true,表示是系统进程,而这次是普通的应用进程,所以参数system为false。ActivityManagerNative.getDefault()方法获取AMS的代理,调用attachApplication方法发送一个进程间通信的请求,将创建的ApplicationThread对象传递给AMS服务。

ApplicationThread是一个ActivityThread本地binder对象,Binder的服务端在ActivityThread中,将Binder对象传递给AMS服务,则AMS服务中保存它的代理,AMS就获得了与新进程通信的方式。

此前的代码实在新建的进程中,即应用App2所在的进程,然后通过进程间通信,下面的代码再次进入AMS服务中。

25. AMS.attachApplication

          ApplicationInfo appInfo = app.instrumentationInfo != null
                    ? app.instrumentationInfo : app.info;
                    
            //进程间调用:调用新进程的bindApplication方法
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
         ……
         
        if (normalMode) {
            try {
                //调用ActivityStackSupervisor的方法来启动新的Activity
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            }
        ……
    }

attachApplication方法获得调用进程的ID之后,直接调用attachApplicationLocked方法继续执行。

attachApplicationLocked方法主要工作

首先根据进程ID,从mPidsSelfLocked中查找对应进程的ProcessRecord,这个ProcessRecord就是新进程的对象,只不过它之前没有指向任何进程,因为新的进程还没有创建。现在新进程已经创建完成,所以需要将它指向新的进程。

从PMS服务中查询新进程相关的ContentProvider的信息,然后通过进程间通信请求,调用thread的bindApplication方法。这个thread就是新进程的ApplicationThread的代理端Binder对象,通过它最终调用到新进程中ActivityThread的handleBindApplication方法。来进一步处理新进程的运行环境的初始化。主要是新进程Application的初始化,Instrumentation的初始化和安装相关的ContentProvider.。

交给ActivityStackSupervisor来继续处理attchApplication逻辑。

26. ActivityStackSuperVisor. attachApplicationLocked

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        final String processName = app.processName;
        //遍历所有的stack,找到处于前台的ActivityStack
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                if (!isFrontStack(stack)) {
                    continue;
                }
                //找到处于栈顶的ActivityRecord
                ActivityRecord hr = stack.topRunningActivityLocked(null);
                if (hr != null) {
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            //调用realstartActivityLocked方法来启动目标Activity
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                          ……
            }
        }

此方法的主要工作就是遍历并找到目标stack,然后拿到这个ActivityStack栈顶的ActivityRecord,这就是目标Activity,是我们之前放到栈顶的。得到要启动的Activity信息之后,做了这么多的准备工作,终于要真正来启动新的Activity了。


Activity启动第三部分

第四步:启动Activity B

27. ActivityStackSuperVisor. realStartActivityLocked

 final boolean realStartActivityLocked(ActivityRecord r,
            ProcessRecord app, boolean andResume, boolean checkConfig)
            throws RemoteException {
            ……
            //将新进程的信息保存到ActivityRecord的app变量中
            r.app = app;
            
            //获取目标Task
            final TaskRecord task = r.task;
            
            //找到Task对用的Stack
            final ActivityStack stack = task.stack;
            
            //跨进程调用,通知目标进程来启动Activity
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

这个方法中首先将ActivityRecord的app对象指向了新的进程,这样ActivityRecord就和新的进程关联了起来。

然后通过目标进程ApplicationThread代理Binder对象发起进程间通信请求,调用目标进程的scheduleLaunchActivity方法来启动新的Activity.

此处代码通过跨进程调用再次进入到了目标进程中。

28. ApplicationThread. scheduleLaunchActivity

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig,…… ProfilerInfo profilerInfo) {
 
            updateProcessState(procState, false);
            //根据进程间传递的消息,初始化ActivityClientRecord
            ActivityClientRecord r = new ActivityClientRecord();
 
            r.token = token;
            r.ident = ident;
            ……
            //发送消息,最终有Handler来处理
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

调用到ActivityThread内部的ApplicationThread中,该ApplicationThread实现了ApplicationThreadNative,这样就实现了进程间通信的Binder服务端。Binder进程间通信不在详细解释

最终发送消息,有Handler的HandMessage来处理。在handleMessage中又调用了ActivityThread的handleLaunchActivity来处理。

29. ActivityThread.handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
 
    //调用performLaunchActivity方法来启动Activity
      Activity a = performLaunchActivity(r, customIntent);
    //Activity启动完成后,调用handlResumeActivity来使Activity进入resume激活状态
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed);
……

首先调用performLaunchActivity来创建一个Activity对象,并调用Activity的onCreate方法完成Activity启动,随后调用handleResumeActivity方法,激活Activity,时Activity计入resume状态。

30. ActivityThread.performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
     ActivityInfo aInfo = r.activityInfo;
    //获取Activity的packageInfo信息
        if (r.packageInfo == null) {
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
    //获取Activity的Component信息
        ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }
        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }
 
    调用Instrumentation类来创建一个根据Activity的信息Activity对象
        Activity activity = null;
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
 
     //创建完成后,调用Activity的attach方法来初始化Activity
     if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor);
 
    ……
    //调用Activity的onCreate方法
    mInstrumentation.callActivityOnCreate(activity, r.state);
 
    ……
    //执行Activity的onStart方法
    if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
    ……
    //调用Activity的onRestoreInstancestate方法
    if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
    ……
    //调用Activity的onPostCreate方法
     mInstrumentation.callActivityOnPostCreate(activity, r.state);
 
         ……
    //把创建的对应的ActivityClientRecord以binder为键值,保存到mActivities中
     mActivities.put(r.token, r);

在新的进程中,根据AMS传递过来的信息创建了一个ActivityClientRecord对象,该对象和AMS服务中的一个ActivityRecord对应。

在这个方法中,根据目标Activity B的ActivityClientRecord,最终调用Instrumentation类来创建一个Acitivity,创建过程就是ClassLoader加载对应的Activity类,用反射方法创建一个对象。

创建完新的Activity对象后,即Activity B的对象,然后调用它的onCreate方法,这样Activity B的onCreate对象就会被调用,以便加载自己定义的用户界面,以及其他的初始化方法。

onCreate方法调用完成之后,然后依次调用Activity的onStart,onRestoreInstanceState,onPostCreate方法等。这个就是Activity生命周期执行的逻辑。

到此为止,ActivityB就启动完成了,它启动起来之后,意味着ActivityB所在的应用程序也就启动起来了。


image.png

Activity整体启动流程时序图如下:

Activity启动流程.jpg

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

推荐阅读更多精彩内容