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

activity是Android中最为重要的组件之一,几乎全部的Android应用都离不开Activity的支撑。所以了解activity的启动流程,掌握activity的工做原理,对于咱们应用层开发人员来讲是很是有意义的。本文对activity的整个启动流程作了一下整理,但愿能对你们有所帮助。java

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

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

Activity的启动主要能够分为两种状况:markdown

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

不管是上述哪一种状况,实际上都是经过调用Activity类的startActivity方法(或是调用startActivityForResult方法来但愿新页面可以返回一个结果)来启动新的Activity。所以,想要理清activity的启动流程,咱们首先就要从startActivity方法开始入手。app

startActivity方法的源码以下:ide

源码路径:\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源码以下:post

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方法:ui

源码路径:\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方法中调用该方法时传入的内容进行一下对比,以便搞清这些参数的含义:this

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

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

经过对比咱们不难猜出这些参数的含义:spa

  • 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的启动流程(二):应用进程部分

相关文章
相关标签/搜索