Activity的启动流程(一):ActivityManagerService部分

761

activity是Android中最为重要的组件之一,几乎所有的Android应用都离不开Activity的支撑。因此了解activity的启动流程,掌握activity的工作原理,对于我们应用层开发人员来说是非常有意义的。本文对activity的整个启动流程做了一下整理,希望能对大家有所帮助。

注:本文基于Android8.0.0源码编写

1.应用进程向AMS发起请求

Activity的启动主要可以分为两种情况:

  • 第一种情况是要启动的Activity所在的应用程序进程尚未被创建,比如我们从桌面点击某个应用的图标,企图打开该应用中的起始Activity时,由于该应用尚未启动,因此android系统会先去创建一个新的进程,然后才能展示要启动的Activity页面。
  • 第二种情况是要启动的Activity所在的进程已经存在了,比如我们点击应用中的某个Button来启动本应用中的另一个Activity,只要目标Activity没有进行过特别声明,那么会在当前进程中创新新的Activity,无需开启新的线程。

无论是上述哪种情况,实际上都是通过调用Activity类的startActivity方法(或是调用startActivityForResult方法来希望新页面能够返回一个结果)来启动新的Activity。因此,想要理清activity的启动流程,我们首先就要从startActivity方法开始入手。

startActivity方法的源码如下:

源码路径:\frameworks\base\core\java\android\app\Activity.java

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

可以看到,startActivity方法最终也会走到startActivityForResult方法中。startActivityForResult源码如下:

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
            
           ...
           
            //注释1
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options); 
                    
           ...
        
    }

注释1处的代码是startActivityForResult方法的核心代码,该行代码将启动activity的工作交给了一个Instrumentation对象。Instrumentation是应用和系统交互的一个中介,接下来我们就来看一下Instrumentation的execStartActivity方法:

源码路径:\frameworks\base\core\java\android\app\Instrumentation.java

    public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
            
        IApplicationThread whoThread = (IApplicationThread) contextThread;
        ...

            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        ...
    }

在阅读execStartActivity方法之前,我们需要先看一下该方法所接受的参数,我们将该方法接收的参数和在startActivityForResult方法中调用该方法时传入的内容进行一下对比,以便搞清这些参数的含义:

//调用时传入的参数
execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);

//方法的定义
execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options)

通过对比我们不难猜出这些参数的含义:

  • Context who:该参数是一个Context对象,在调用execStartActivity时传入的是“this”,即当前activity。该参数代表启动新activity的发起方的上下文环境。
  • IBinder contextThread:该参数传入的是mMainThread.getApplicationThread(),这是一个IBinder对象,代表了当前应用进程。
  • IBinder token:发起方的标识,系统使用该标识来辨别是谁要启动一个新activity。该参数传入的是Activity的成员变量mToken,该对象是Activity创建时被赋予的。
  • Activity target:代表启动新activity的任务是由哪个activity发起的。
  • Intent intent:即我们平时在调用startActivity方法时传入的intent,封装了启动activity的一些信息。
  • int requestCode:如果希望从新页面返回结果则需要用该参数作为标识,如果该参数的值小于0则代表不需要从新页面返回结果。
  • Bundle options:其他附加数据。

搞懂了这些参数的含义,我们再来看execStartActivity的内容,可以看到在execStartActivity方法中主要是调用了ActivityManager.getService().startActivity来进一步执行启动activity的工作。我们先来看一下ActivityManager.getService()究竟返回的是什么:

    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                
                    //注释2
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
    };

通过分析源码我们可以发现,getService返回的是一个IActivityManager对象,并且该对象使用了单例模式。在注释2处,首先通过ServiceManager.getService来获取了一个IBinder,然后通过IActivityManager.Stub.asInterface(b)这行代码将这个Binder对象转化为了IActivityManager类型。有了解过AIDL的实现方式的同学应该不能看出,IActivityManager.Stub.asInterface正是标准的AIDL实现方式,而这里获取到的这个IActivityManager对象,正是系统服务ActivityManagerService的本地代理对象。

ActivityManagerService(简称AMS)是Android系统的一个非常重要的系统服务,它是在android系统启动时创建的,并由SystemService进行管理。AMS主要负责管理android系统中各应用的activity页面,控制activity对象的生命周期等,因此,当我们的应用进程要启动一个新的Activity时,自然要和AMS进行通信。从上面的代码可以看出,8.0之后的系统使用的是AIDL来和AMS进行通信的(注:在8.0之前是并不是使用的AIDL)。

当通过ActivityManager.getService()获取到了这个IActivityManager对象之后,又调用了该对象的startActivity方法,由于这个IActivityManager实际上是AMS在客户端的一个代理,因此此处实际上是调用的AMS的startActivity方法。至此,android的启动由应用进程进入到了AMS进程中。

2.AMS处理相关请求

我们来看一下AMS的startActivity方法的源码:

源码路径:\frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java

    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }
    
    @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
		...
        
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }
    
    

可以看到,在startActivity中调用了startActivityAsUser方法,在startActivityAsUser中又调用了mActivityStarter的startActivityMayWait方法,我们来看一下startActivityMayWait方法的源码:

源码路径:\frameworks\base\services\core\java\com\android\server\am\ActivityStarter.java

    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 globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {

		...
        
        synchronized (mService) {
            ...
            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
            ...
        }
        ...
    }
    
    int startActivityLocked(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, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask, String reason) {

        ...

        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask);

        ...
        return mLastStartActivityResult;
    }

startActivityMayWait方法的代码很长,但最核心的代码则是调用了startActivityLocked方法来进一步启动Activity,而在startActivityLocked方法中又调用了startActivity方法,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, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
            
            ...
            
            //注释1
            ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
                
            ...
            
            //注释2
            return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
    }        

在注释1处,系统将要被启动的Activity的各类信息封装到了一个ActivityRecord对象中。ActivityRecord是activity在AMS中的一个记录,可以理解为每个ActivityRecord都代表着一个Activity实体。之后,在注释2处又调用了另一个startActivity的重载方法,我们看一下该方法的源码:

	private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } 
		
		...

        return result;
    }

可以看到startActivity方法又调用了startActivityUnchecked方法:

    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {

        ...

        // 注释1: 如果要被启动的activity和当前在栈顶的activity是同一个
        // 那么需要检查要被启动的activity是否只允许被启动一次
        final ActivityStack topStack = mSupervisor.mFocusedStack;//获取当前最顶部的activity栈
        final ActivityRecord topFocused = topStack.topActivity();//获取当前栈顶的activity
        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
        
        // 判断是否应该启动一个新的activity
        // 如果要启动的activity和当前栈顶的activity是同一个,并且要启动的activity的启动模式为
        // FLAG_ACTIVITY_SINGLE_TOP,则不需要进行启动
        final boolean dontStart = top != null && mStartActivity.resultTo == null
                && top.realActivity.equals(mStartActivity.realActivity)
                && top.userId == mStartActivity.userId
                && top.app != null && top.app.thread != null
                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                || mLaunchSingleTop || mLaunchSingleTask);
        if (dontStart) {
            
            ...
			
            if (mDoResume) {
                mSupervisor.resumeFocusedStackTopActivityLocked();
            }
            ...

            return START_DELIVERED_TO_TOP;
        }

        ...
		
        //注释2:检查是否应该创建一个新的activity任务栈
        // 在启动模式设置为FLAG_ACTIVITY_NEW_TASK的情况下会新建一个activity任务栈来存放要启动的activity
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
			//创建新任务栈
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } else if (mSourceRecord != null) {
			//使用发起请求的activity的任务栈来存放要被启动的activity
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        }
		
        ...

        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                mWindowManager.executeAppTransition();
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                //注释3
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }

        ...

        return START_SUCCESS;
    }

startActivityUnchecked方法的代码较长,但逻辑并不复杂。先来看注释1处的几行代码,这里主要是为了处理要被启动的activity的启动模式为SINGLE_TOP的情况。在注释1处,首先获取了当前处于栈顶的activity的信息,然后判断要被启动的activity和当前处于栈顶的activty是否是同一个。如果要被启动的activity和当前处于栈顶的actiivty是同一个activity,并且要被启动的activity的启动模式被设置为了FLAG_ACTIVITY_SINGLE_TOP,那么系统不会继续去重新启动一个新的activity实例,而是直接复用当前栈顶的activity,并返回START_DELIVERED_TO_TOP,后面的代码也不会再执行了。

注释2处的代码主要是用来判断要被启动的activity是否要放入到一个新的任务栈中。我们都知道,如果activity的启动模式被设置为了NEW_TASK,那么该activity会被放入一个单独的任务栈中。从注释2出的代码我们可以看出,如果要被启动的activity被设置了FLAG_ACTIVITY_NEW_TASK标识,那么系统会为该activity创建一个新的activity任务栈。

之后系统会判断要被启动的activity是否可以获取焦点等信息,然后通过注释3处的代码来继续启动activity,我们来看一下mSupervisor的resumeFocusedStackTopActivityLocked方法。

代码路径:\frameworks\base\services\core\java\com\android\server\am\ActivityStackSupervisor.java

    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        //注释1
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //注释2
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } 
        ...
        return false;
    }

在注释1处,如果targetStack不为null并且targetStack拥有焦点,那么会执行targetStack的resumeTopActivityUncheckedLocked方法。 在注释2处获取到了栈中正在运行的最顶端的一个ActivityRecord,如果r为null或者r的状态不是RESUMED,则会执行 mFocusedStack的resumeTopActivityUncheckedLocked方法。targetStack和mFocusedStack都是ActivityStack类型的对象,我们来看一下ActivityStack的resumeTopActivityUncheckedLocked方法:

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        ...
       
        try {
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        }
        
        ...

        return result;
    }

resumeTopActivityUncheckedLocked方法又调用了resumeTopActivityInnerLocked方法:

    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        
		...
		
        if (mResumedActivity != null) {
            if (DEBUG_STATES) Slog.d(TAG_STATES,
                    "resumeTopActivityLocked: Pausing " + mResumedActivity);
            //注释1
            pausing |= startPausingLocked(userLeaving, false, next, false);
        }
        
		...

        if (next.app != null && next.app.thread != null) {
			
            ...

        } else {
            ...
            //注释2
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }

        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        return true;
    }

在注释1处,如果当前存在已经处于前台展示的activity,则会先调用startPausingLocked方法将当前处于展示状态的activity转为pasue状态。

在通常情况下,代码会执行到注释2处,此处调用了mStackSupervisor对象的startSpecificActivityLocked方法来继续activity的启动,该方法源码如下:

    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        
	//注释1:根据要被启动的activity的信息获取其所在的进程信息
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.getStack().setLaunchTime(r);

	//注释2:如果要启动的activity的所在进程存在
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
				//注释3
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }

	//注释4
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

在注释1处,系统首先根据要被启动的activity的信息来获取其所在的进程的信息,在注释2处对获取到的app对象进行了判断,如果app不位null并且app的thread(即ActivityThread)也不为空,说明要启动的activity的进程存在,那么会调用注释3处的realStartActivityLocked方法来进一步启动activity,否则会调用注释4处的startProcessLocked方法来创建一个新进程。

创建新进程的过程比较复杂,会放在之后的文章中进行专门介绍,这里先来看进程已经存在的情况。realStartActivityLocked源码如下:

    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {

        ...
        try {
            ...

            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);

            ...

        } 

        ...

        return true;
    }

在realStartActivityLocked方法中直接调用了app.thread.scheduleLaunchActivity来启动Activity。app即要启动的activity所在的进程,thread即该进程的ActivityThread,这是一个Binder对象,因此,app.thread.scheduleLaunchActivity实际上是跨进程调用,实际上调用的是要启动的activity所在进程的ActivityThread对象中的scheduleLaunchActivity方法。至此,activity的启动流程就从AMS中转到了目标应用进程中。

总结

我们对这部分的启动流程进行一下概括总结:

  1. 应用程序通过Binder机制向AMS发起启动新Activity的请求
  2. AMS接收到请求,根据启动模式生成或调整相关的ActivityRecord、TaskRecord等对象
  3. 如果当前存在一个已经在前台的Activity,则需要将这个activity置为pause状态
  4. 如果要启动的activity所在的应用的进程尚未创建,则去创建新的进程
  5. 如果要启动的activity所在的应用的进程已经存在,则通知该进程的ActivityThread来继续进行activity的启动

下篇:Activity的启动流程(二):应用进程部分