深入分析Android 9.0源代码——Activity启动流程

引言

点击此处查看《深入分析Android 9.0源代码》系列的组织结构和相关说明。


1 应用进程发起启动请求

本章的调用流程如下图所示:

(Context) Activity Instrumentation ActivityManager [1-2] startActivity() [3-4] startActivityForResult() [5] execStartActivity() [6] getService() (Context) Activity Instrumentation ActivityManager

注:
(1)由于编辑器渲染的时序图不支持“无触发对象消息”(在标准的时序图中,这种消息的起点为实心圆形,表示流程的开始),此处用“(Context)”虚指触发流程的起始对象。
(2)对于时序图中形如“A—[#num] method()—>B”的消息(连线为实线),它的含义是控制流由先前的对象A(直接)转移到对象B,然后调用对象B的编号为#num的method()方法。
(3)同名的重载方法调用会直接合并,其对应的方法编号也使用[#num1-#num2]的形式进行合并。


1.1 startActivity(ForResult)@Activity

Activity类的startActivity()对于Android开发者来说可谓是再熟悉不过了。作为应用进程启动Activity的入口,经过一系列方法重载调用后,startActivity()最终会调用startActivityForResult(),并且传入-1和null作为参数requestCodeoptions的值。

// #1 {root}/core/java/ android.app.Activity (L4872)
public void startActivity(Intent intent) {
   
    this.startActivity(intent, null); // 调用#2
}

// #2 {root}/core/java/ android.app.Activity (L4899)
public void startActivity(Intent intent, Bundle options) {
   
    if (options != null) 
        startActivityForResult(intent, -1, options);
    else
        startActivityForResult(intent, -1); // 调用#3
}

// #3 {root}/core/java/ android.app.Activity (L4543)
public void startActivityForResult(Intent intent, int requestCode) {
   
    startActivityForResult(intent, requestCode, null); // 调用#4
}

// #4 {root}/core/java/ android.app.Activity (L4581)
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
   
    ...
}


1.2 startActivityForResult@Activity

startActivityForResult()委托Instrumentation对象的execStartActivity()执行Activity的启动流程,然后对其返回的启动结果进行处理。

// #4 {root}/core/java/ android.app.Activity (L4581)
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
   
    if (mParent == null) {
   
        ...
        Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
               this, mMainThread.getApplicationThread(), mToken, 
               this, intent, requestCode, options); // 调用#5
        if (ar != null)
            mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
        if (requestCode >= 0) 
            mStartedActivity = true;
        ...
    }
    ...
}

【L-03】if (mParent == null) { … }
mParent是一个Activity类型的成员变量,它记录了当前Activity的父Activity。Activity之间的父子关系既可以通过在Manifest中设置android:parentActivityName属性来实现1,也可以由继承自ActivityGroup的类(例如TabActivity)来定义2(官方在API 13后已经弃用了ActivityGroup,并推荐使用Fragment作为替代3)。因此,通常情况下mParent的取值为null,从而后续代码进入if分支。

【L-05】Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(…);
mInstrumentation是一个Instrumentation类型的成员变量,简单来说可以理解为应用进程的“管家”。每个应用程序有且仅有一个Instrumentation对象,并且每个Activity内部都持有对它的引用4。此处通过调用Instrumentation对象的execStartActivity(),将后续的Activity启动流程委托给这位得力的“管家”来完成,然后从返回值ar中获取并处理对应的启动结果(事实上该值默认为null,具体原因参见下文1.3节)。

【L-09】mMainThread.sendActivityResult(…);
mMainThread是一个ActivityThread类型的成员变量,它就是“通常所说”的主线程(UI线程)。此处调用ActivityThread的sendActivityResult(),将包括execStartActivity()的返回值ar在内的启动结果(通过Handler)转发出去5。需要特别指出的是,ActivityThread并没有继承自Thread类,严格来说它只是一个“运行在主线程的对象”。当一个Android应用进程被创建后,虚拟机会预先创建一个主线程6,然后在主线程中执行ActivityThread类的main方法(具体流程参见下文5.1节)。而真正意义上的“主线程Thread实例”虽然存在,但它的创建过程由虚拟机进行管理,所以相关的代码是不可见的7。综上所述,对于“主线程”这个概念比较严谨的描述是“ActivityThread对象所运行的线程”8,而本文为了表述方便,仍会将ActivityThread直接称为主线程。

【L-12】mStartedActivity = true;
mStartedActivity是一个boolean类型的成员变量,当方法参数requestCode为非负值(即满足判断条件requestCode>=0)时,该变量被置为true,表明被启动的Activity关闭(调用finish())后会返回一个(通过事先调用setResult()设定的)结果给当前Activity9。在收到返回的结果之前,当前Activity将一直保持不可见的状态10


1.3 execStartActivity@Instrumentation

execStartActivity()获取系统服务ActivityManagerService(下文简称为AMS,它所属的system_server系统进程简称AMS进程)的Binder代理对象,然后将Activity的启动请求通过IPC(进程间通信)发送给AMS进行处理。由于AIDL实现的IPC默认是同步的,所以应用进程的当前线程将会挂起,直到AMS进程的startActivity()返回。需要特别注意的是,虽然该方法本身是同步调用,但是后续AMS处理Activity的启动过程是异步的,也即AMS进程的startActivity()并不会一直阻塞直到Activity启动完毕11。事实上,当应用进程调用的execStartActivity()返回时(默认实现为返回null,开发者出于一些特殊目的可以重写该方法并显式指定返回值,从而强制要求应用进程处理特定的启动结果),AMS并不保证目标Activity已经创建成功(如果需要)并且执行了相应的回调方法。

// #5 {root}/core/java/ android.app.Instrumentation (L1635)
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() // 调用#6
                                .startActivity(whoThread, who.getBasePackageName(), intent,
                                            intent.resolveTypeIfNeeded(who.getContentResolver()), 
                                            token, target != null ? target.mEmbeddedID : null, 
                                            requestCode, 0, null, options); // IPC调用#7
    checkStartActivityResult(result, intent);
    ...
    return null;
}

【L-04】IApplicationThread whoThread = (IApplicationThread) contextThread;
该赋值语句中涉及类型为IBinder的参数contextThread,以及类型为IApplicationThread的局部变量whoThread。首先来分析contextThread,这个参数的值在上文1.2节分析过的caller方法startActivityForResult()中对应于mMainThread.getApplicationThread()。先前已提到mMainThread就是主线程,它的getApplicationThread()返回ApplicationThread类型的成员变量mAppThread。简单来说,mAppThread是一个Binder实体对象,它作为server端等待来自client端(即AMS)的请求然后进行处理12。接着再分析whoThread,它就是刚才提到过的ApplicationThread对象,由于它实现了AIDL接口IApplicationThread,所以此处可以进行类型转换。

【L-06】int result = ActivityManager.getService().startActivity(…);
先前提到,应用进程和AMS进程通过Binder机制进行通信,并且ApplicationThread对象在应用进程中作为server端,接收来自AMS的消息。那么反过来也能自然地想到,当应用进程作为client端主动向AMS发送请求时,同样也需要借助于类似的Binder代理对象,而它正是调用ActivityManager.getService()获得的IActivityManager类型的对象。随后调用的IActivityManager的startActivity(),实质上是通过AIDL调用AMS的startActivity()13

【L-11】checkStartActivityResult(result, intent);
checkStartActivityResult()的方法名就能看出,它对AMS调用startActivity()的返回值进行检查,如果由于缺少权限、类加载失败、Intent解析错误等原因导致Activity无法正常启动时,就会抛出对应的异常。例如,当Activity没有在Manifest中注册时,就会抛出开发者熟悉的ActivityNotFoundException异常,其中包含的异常信息为“Unable to find explicit activity class XXX; have you declared this activity in your AndroidManifest.xml?”。


1.4 getService@ActivityManager

上文1.3节中execStartActivity()获取的Binder代理对象是一个单例对象,它由应用进程中的ActivityManager类进行管理。

// #6 {root}/core/java/ android.app.ActivityManager (L4125)
public static IActivityManager getService() {
   
    return IActivityManagerSingleton.get();
}

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

【L-03】return IActivityManagerSingleton.get();
getService()返回静态常量IActivityManagerSingleton(注意这个变量命名不够规范,容易被误认为是一个类),它是一个IActivityManager单例对象,所有应用进程都通过这个唯一的Binder代理对象向AMS发送消息。此处的单例通过android.util包提供的Singleton工具类来实现,该类专门用于构建线程安全的懒加载单例对象14

【L-08】protected IActivityManager create() { … }
create()是Singleton类的抽象方法,它定义了单例对象的初始化流程。首次调用get()时会通过create()来创建单例对象,后续调用get()则会直接返回先前已创建的对象。

【L-09】final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
ServiceManager是Android系统服务的管理者,当一个服务在ServiceManager中注册后,客户进程就能通过调用getService()来查询和获取该服务的Binder代理对象15。此处传入的参数是Context.ACTIVITY_SERVICE,表明需要获取AMS的Binder代理对象。

【L-10】final IActivityManager am = IActivityManager.Stub.asInterface(b);
Binder对象在获取后并不能直接使用,还需要调用asInterface()将服务端的Binder对象转换为客户端所需的AIDL接口类型的对象。虽然Android提供的Binder机制可以实现进程间的通信,但是当服务端和客户端都在同一个进程时,IPC实为多此一举,此时直接通过本地方法调用即可进行通信16。因此,asInterface()在转换Binder对象时,会对服务端和客户端属于“相同进程”和“不同进程”这两种情况分别处理,从而返回一个对于客户端而言“最经济适用”的AIDL接口对象。


2 AMS处理启动请求

本章的调用流程如下图所示:

ActivityManager [AMS] ActivityStarter [ASS] ActivityStack [7] startActivity() [8-9] startActivityAsUser() [10] execute() [11] startActivityMayWait() [12-14] startActivity() [15] startActivityUnchecked() [16] resumeFocusedStackTopActivityLocked() [17] resumeTopActivityUncheckedLocked() [18] resumeTopActivityInnerLocked() ActivityManager [AMS] ActivityStarter [ASS] ActivityStack

注:由于编辑器限制对象文本的最大长度,时序图中对于名称较长的类使用方括号(“[]”)和缩写来表示。上图中[AMS]=ActivityManagerService, [ASS]=ActivityStackSupervisor。


2.1 startActivity(AsUser)@ActivityManagerService

作为AMS处理启动请求的入口方法,startActivity()经过两次方法重载调用,最终会调用startActivityAsUser()并额外传入两个与调用者权限检查相关的参数userIduserIdvalidateIncomingUser(后者直接赋值为true)。

// #7 {root}/services/core/java com.android.server.am.ActivityManagerService (L5079)
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()); // 调用#8
}

// #8 {root}/services/core/java com.android.server.am.ActivityManagerService (L5088)
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 startActivityAsUser(caller, callingPackage, intent, resolvedType, 
            resultTo, resultWho, requestCode, startFlags, profilerInfo, 
            bOptions, userId, true); // 调用#9
}

// #9 {root}/services/core/java com.android.server.am.ActivityManagerService (L5096)
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, boolean validateIncomingUser) {
   
    ...
}


2.2 startActivityAsUser@ActivityManagerService

startActivityAsUser()对参数userId进行权限检查,然后将Activity启动请求转发给新创建的ActivityStarter对象。

// #9 {root}/services/core/java com.android.server.am.ActivityManagerService (L5096)
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, boolean validateIncomingUser) {
   
    ...
    userId = mActivityStartController.checkTargetUser(userId, validateIncomingUser, 
            Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
    return mActivityStartController.obtainStarter(intent, "startActivityAsUser").
            setCaller(caller).
            setCallingPackage(callingPackage).
            setResolvedType(resolvedType).
            setResultTo(resultTo).
            setResultWho(resultWho).
            setRequestCode(requestCode).
            setStartFlags(startFlags).
            setProfilerInfo(profilerInfo).
            setActivityOptions(bOptions).
            setMayWait(userId).
            execute(); // 调用#10
}

【L-09】userId = mActivityStartController.checkTargetUser(…);
mActivityStartController是一个ActivityStartController类型的成员变量,此处调用obtainStarter()创建ActivityStarter对象,然后调用一系列setX()方法配置ActivityStarter对象的参数,最后调用execute()让ActivityStarter对象接管Activity的启动请求。

【L-19】…setMayWait(userId)…
setMayWait()将ActivityStarter对象的成员变量mRequest.mayWait设置为true,该参数的作用将在下文2.3节中进行分析。


2.3 execute@ActivityStarter

execute()根据boolean变量mRequest.mayWait的值(在本文分析的执行流程中为true)调用对应的方法。

// #10 {root}/services/core/java com.android.server.am.ActivityStarter (L481)
int execute() {
   
    ...
    if (mRequest.mayWait) {
   
        return startActivityMayWait(mRequest.caller, mRequest.callingUid, mRequest.callingPackage, 
                mRequest.intent, mRequest.resolvedType, mRequest.voiceSession, 
                mRequest.voiceInteractor, mRequest.resultTo, mRequest.resultWho, 
                mRequest.requestCode, mRequest.startFlags, mRequest.profilerInfo, 
                mRequest.waitResult, mRequest.globalConfig, mRequest.activityOptions,
                mRequest.ignoreTargetSecurity, mRequest.userId, mRequest.inTask, mRequest.reason,
                mRequest.allowPendingRemoteAnimationRegistryLookup); // 调用#11
    }
    ...
}

【L-04】if (mRequest.mayWait) { … }
上文2.2节中caller方法startActivityAsUser()通过调用setMayWait()mRequest.mayWait设置为true,故此处会执行if分支。

【L-09】return startActivityMayWait(…, mRequest.waitResult, …);
上文2.2节中caller方法startActivityAsUser()没有调用过setWaitResult(),所以参数mRequest.waitResult的值为null,它的作用将在下文2.4节中进行分析。


2.4 startActivityMayWait@ActivityStarter

startActivityMayWait()的主要流程包括获取callingPid与callingUid、查询Activity对应的ActivityInfo17、调用(比入口方法有更多参数的)startActivity()重载方法执行后续Activity启动流程、判断线程是否需要wait。

// #11 {root}/services/core/java com.android.server.am.ActivityStarter (L945)
private 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, 
        SafeActivityOptions options, boolean ignoreTargetSecurity, int userId, TaskRecord inTask, 
        String reason, boolean allowPendingRemoteAnimationRegistryLookup) {
   
    ...
    final int realCallingPid = Binder.getCallingPid();
    final int realCallingUid = Binder.getCallingUid();
    int callingPid;
    if (callingUid >= 0) 
        callingPid = -1;
    else if (caller == null) {
   
        callingPid = realCallingPid;
        callingUid = realCallingUid;
    }
    else 
        callingPid = callingUid = -1;
    ...
    ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
            computeResolveFilterUid(callingUid, realCallingUid, mRequest.filterCallingUid));
    ...
    ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
    ...
    final ActivityRecord[] outRecord = new ActivityRecord[1];
    int res = startActivity(caller, intent, ephemeralIntent, resolvedType, aInfo, rInfo, 
            voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, 
            callingUid, callingPackage, realCallingPid, realCallingUid, startFlags, 
            options, ignoreTargetSecurity, componentSpecified, outRecord, inTask, 
            reason, allowPendingRemoteAnimationRegistryLookup); // 调用#12
    ...
    if (outResult != null) {
    ... }
    ...
}

【L-21】ResolveInfo rInfo = mSupervisor.resolveIntent(…);
mSupervisor是一个ActivityStackSupervisor类型的成员变量,它是Android系统中Activity的栈管理器18,与Activity启动模式相关的android:launchMode属性和Intent的Flags参数正是由它负责处理。此处调用resolveIntent()返回的rInfo是一个ResolveInfo类型的局部变量,它实现了Parcable接口,用于维护解析Intent后得到的信息19。事实上ResolveInfo对象部分地对应于从Manifest的<intent>标签收集到的信息,例如应用的包名、类名、图标等。

【L-24】ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
当目标Activity通过隐式Intent来启动时,resolveActivity()负责解析传入的参数intentresolveTypeflag,从符合条件的Activity集合中选择一个“最匹配”的Activity作为目标Activity(当系统无法确定哪个Activity“最匹配”时会提示用户自行选择),然后返回用于描述其相关信息的ActivityInfo对象20

【L-26】final ActivityRecord[] outRecord = new ActivityRecord[1];
此处为目标Activity创建了一个长度为1的ActivityRecord数组outRecord,但是并没有立即为数组中的唯一元素赋值(具体的赋值过程将在下文2.5节中进行分析)。ActivityRecord对象用于描述Activity栈中的Activity实例,由于Activity可以被多次实例化(取决于Manifest中Activity的android:launchMode属性和Intent的Flags参数),从而同一个Activity可能会存在多个对应的ActivityRecord对象21

【L-33】if (outResult != null) { … }
outResult不为null时,if分支内部会调用service.wait()使线程进入wait状态,这正是方法名“startActivityMayWait”中“MayWait”一词的由来22。由于上文2.3节中caller方法execute()传入的参数mR

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值