欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android四大组件之Activity启动流程源码实现详解(一)

程序员文章站 2022-03-16 15:02:09
   Android四大组件之Activity启动流程源码实现详解(一)Activity启动流程源码实现详解系列博客目录:Activity启动流程源码实现详解概要前言  在正式开始Android四大组件之Activity启动流程源码实现详解之前,如果小伙们还没有阅读Activity启动流程源码实现详解概要,强烈建议先行阅读该概要,因为该篇博客从整体概要和Activity启动的前期知识点出发为我们提供了提纲和将要涉及到的知识点的梳理。在本篇博客中我们将重点分析目标进程发送Activity启动请...

      Activity启动流程源码实现详解(一)

Android四大组件源码实现详解系列博客目录:

Android应用进程创建流程大揭秘
Android四大组件之bindService源码实现详解
Android四大组件之Activity启动流程源码实现详解概要
Android四大组件之Activity启动流程源码实现详解(一)


前言

  在正式开始Android四大组件之Activity启动流程源码实现详解之前,如果小伙们还没有阅读Activity启动流程源码实现详解概要,强烈建议先行阅读该概要,因为该篇博客从整体概要和Activity启动的前期知识点出发为我们提供了提纲和将要涉及到的知识点的梳理。在本篇博客中我们将重点分析目标进程发送Activity启动请求和AMS服务对启动Activity的请求的初步处理,即重点阐述如下阶段流程:

  • Souruce端进程发送请求目标Activity启动阶段
    1.Source端发起显示/隐式启动请求启动Activity

  • System_server进程通过AMS处理启动Activity请求
    2.解析启动目标Activity的Intent
    3.创建目标Activity对应的ActivityRecord

  • 注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:

frameworks/base/services/core/java/com/android/server/am/
  --- ActivityManagerService.java
  --- ProcessRecord.java
  --- ActivityRecord.java
  --- ActivityResult.java
  --- ActivityStack.java
  --- ActivityStackSupervisor.java
  --- ActivityStarter.java
  --- TaskRecord.java 

frameworks/base/services/core/java/com/android/server/pm、
 --- PackageManagerService.java

frameworks/base/core/java/android/app/
  --- IActivityManager.java
  --- ActivityManagerNative.java (内部包含AMP)
  --- ActivityManager.java
  --- AppGlobals.java
  --- Activity.java
  --- ActivityThread.java(内含AT)
  --- LoadedApk.java  
  --- AppGlobals.java
  --- Application.java
  --- Instrumentation.java
  
  --- IApplicationThread.java
  --- ApplicationThreadNative.java (内部包含ATP)
  --- ActivityThread.java (内含ApplicationThread)
  --- ContextImpl.java
  • 并且在后续的源码分析过程中为了简述方便,会将做如下简述:
    ApplicationThreadProxy简称为ATP
    ActivityManagerProxy简称为AMP
    ActivityManagerService简称为AMS
    ActivityManagerNative简称AMN
    ApplicationThreadNative简称ATN
    PackageManagerService简称为PKMS
    ApplicationThread简称为AT
    ActivityStarter简称为AS,这里不要和ActivityServices搞混淆了
    ActivityStackSupervisor简称为ASS


一. Source端开始请求执行启动Activity

  Source端开始请求执行启动Activity的核心伪代码如下,接下来我们以下面的伪代码为脉络逐步分析,但是不会每个源码细节都予以分析(并且如果小伙们只是想大概了解一下基本流程,那么下面的伪代码就够了!),而是挑出重点!

//发起端进程发起启动Activity请求
	Activity.startActivity(...)
	  Activity.startActivityForResult(...)
	    mInstrumentation.execStartActivity(...)
		  AMP.startActivity(...)//通过AMS代理端向AMS发起启动Activity的Binder IPC请求
		  mInstrumentation.checkStartActivityResult(...)//检测启动是否成功
		mMainThread.sendActivityResult(...)

2.1 Activity.startActivity

    Intent intent = new Intent();
    intent.setAction("xxx.xxx.xxx");
    startActivity(intent);

  通常我们在Activity启动Activity会直接调用startActivity方法,此时会执行Activity的startActivity方法

//Activity.java
    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }

此时可以看到会接着调用Activity的重载startActivity方法,我们接着继续分析其重载方法

//Activity.java
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);//进入该分支,注意此时的参数requestCode取值为-1,表明发起端进程无需接收Activity的结果,详见章节2.2
        }
    }

此时我们的入参options为null,所以会走入else的分支,即此时的startActivityForResult方法的参数requestCode被默认赋予了-1的值。

  分析到这里不知道小伙们注意到一个问题没有,就是通常我们启动Activity有两个方法startActivity和startActivityForResult。这里我们可以看到Activity中调用startActivity的内部也是调用的startActivityForResult的。
  而我们知道通过startActivityForResult启动目标Activity可以在Activity中回调onActivityResult接收目标Acitiy启动的情况,而调用startActivity则不可以呢?其最最主要的原因就是调用startActivity启动目标Acitivity时,其内部调用startActivityForResult传递的参数requestCode被默认赋予为-1了在后续过程中会根据此值判断是否需要传递回调用结果,这也意味着我们在Activity调用startActivityForResult的时候传递的requestCode值为-1(通过后续分析我们可知,只要小于0)的话,那么onActivityResult是不起作用的。所以当我们调用startActivityForResult的时候需要注意这一点。


2.2 Activity.startActivityForResult

//Activity.java
	Activity mParent;
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
			/*
			* mToken: 数据类型为IBinder,这个Token贯穿AMS,Activity,WMS,并且可以跨进程传递
			* mAppThread: 又是一个IBinder类型,此处它是Binder实体ApplicationThread
			*/
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);//详见2.3
            if (ar != null) {
                mMainThread.sendActivityResult(//发送执行结果
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {//注意此处
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
        } else {//子窗口中会执行此分支
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

  注意这里有一个判断逻辑mParent是否为null,这里的mParent 根据文档注释和实测应该是用来判断是否是在子窗口的,类似于在Dialog中启动Activity中的那种。在当前情况下我们可知为null所以会走入ifi分支。

这里我们需要重点分析一下Instrumentation这个类,Instrumentation是android系统中启动Activity的一个实际操作类,即实际执行者,在有些书中也被成为Activity的大管家。并且这里我们所说的Source端开始请求执行启动Activity实际上就是Instrumentation进行实际操作执行的,那么为什么说是在应用进程端的启动呢?实际上Activity的启动分为应用进程端的启动和system_server服务进程端的启动,Activity的启动不是独立的,而是多个应用进程相互配合最终完成了Activity在系统中的启动的,而在应用进程端的启动实际的操作类就是Intrumentation来执行的。我们来简单看看其提供了那些基本方法:

newActivity(…)
newApplication(…)
callApplicationOnCreate(…)
callActivityOnCreate(…)
callActivityOnNewIntent(…)
callActivityOnXXX(…)
execStartActivity(…)

从上面可以看到它的方法都是Application和Activity的创建以及生命周期的相关方法。

同时这里有一个知识点,我需要提前补充一下就是对于每一个Android App进程来说,它的总入口都是ActivityThread的main. 每一个应用的进程都有且仅有一个ActivityThread对象,而每一个ActivityThread对象有且仅有一个Instrumentation成员变量,即整个App进程中ActivityThread和Instrumentation实例对象是唯一的。


2.3 Instrumentation.execStartActivity

//Instrumentation.java
    public ActivityResult execStartActivity(
            Context who, 
            IBinder contextThread, 
            IBinder token, 
            Activity target,
            Intent intent, 
            int requestCode, 
            Bundle options)

  在正式开始分析该方法前,我得对该方法的参数予以隆重的介绍:

  • who
    参数类型为Context实例,标明发起端上下文的信息

  • contextThread
    参数类型为IBinder实例,该对象继承于ApplicationThreadNative(Binder服务端),这个ApplicationThread对象很重要,因为正是通过它串联其了AMS对发起端进程的ActivityThread的交互(如果把ApplicationThread当作服务端,那么此时AMS相关于ApplicationThread而言就是客户端)。其两者之间的关系建立详见下述的示意图,即AMS持有ApplicationThread的代理端,而应用端进程持有AMS的代理端AMP,二者相互持有各自Binder服务端的代理端进而完成了二者之间的RPC调用。在目标Activiy启动后发起端Activity的onPause的执行是由其代理端ATP在AMS中来通过Binder IPC透传过来,然后发起端Activity执行onPause流程Android四大组件之Activity启动流程源码实现详解(一)

  • token
    参数类型也为IBinder实例,指向发起端Activity的ActivityRecord对象中的Token,其Binder实体在AMS中,这里暂且不表

  • target
    参数类型为Activity实例,标明发起端Activity,如果发起端不为Activity此时为null

  • intent
    参数类型为Intent实例,用来表明要启动的Activity信息,此时的intent可能是显示Intent,也可能是隐式Intent,我们此处的是一个隐式Intent。显式intent通常用在包内启动组件,如果是启动其他APP的组件,则通常用隐式intent。显式intent里面包含了一个ComponentName,ComponentName由包名 + 类名组成,可以唯一标识一个组件,系统通过ComponentName就可以找到要启动的组件。隐式intent通常通过Action来过滤出要启动的组件

  • requestCode
    参数类型为int,启动Activity的请求码,此请求码表明发起端是否需要接收目标Activity启动的结果

  • options
    参数类型为Bundle ,可以理解我启动目标Activity的附件参数,譬如附件传输的一些额外信息

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

        IApplicationThread whoThread = (IApplicationThread) contextThread;
		..
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);

			/* public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
						String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
			   			ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
			   caller:当前应用的ApplicationThread对象mAppThread
			   callingPackage: 调用当前ContextImpl.getBasePackageName(),获取当前Activity所在包名
			   intent: 这便是启动Activity时,传递过来的参数
			*/

            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);//详见章节2.4
            checkStartActivityResult(result, intent);//检查Activity启动是否成功
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }

2.4 AMN.getDefault

  继续回到章节2.3,我们可以看到最后其调用了AMN.getDefault().startActivity,这里牵涉到一个重要的方法AMN.getDefault(),其实它在我们的博客中 Android Binder框架实现之Java层获取Binder服务源码分析已经有详细的介绍和分析了,但是为了博客的连贯性还是简单过下(主要是为了不太熟悉的小伙伴们)。

//ActivityManagerNative.java
    static public IActivityManager getDefault() {
        return gDefault.get();
    }

这里的gDefault是Singleton对象实例,而Singleton我们可以看到是一个模板类对象,并且提供了一个单例方法,其定义如下:

//Singleton.java
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {//采用单例模式
                mInstance = create();
            }
            return mInstance;
        }
    }
}

我们将IActivityManager带入Singleton,得到如下的create方法过程:

	//ActivityManagerNative.java
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
        	//此处等价于IBinder b = new BinderProxy(new BpBinder(handle));
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
			//此处等价于IActivityManager am = new ActivityManagerProxy(new BinderProxy(new BpBinder(handle)))
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };

	//注意此处我们的入参是BinderProxy类型,所以会走代理端
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
		//即会走到此处
        return new ActivityManagerProxy(obj);
    }

这里即最终经过层层转换得到了AMS服务的代理端ActivityManagerProxy,进而借助它完成对AMS服务的RPC请求。

2.4.1 AMN.getDefault()小结

AMN.getDefault()的调用流程基本分析结束了,我们对其小结一下:

  • AMN.getDefault()最终获取了AMS的远程Binder代理端AMP
  • AMS的Binder通信过程中提供了一个IActivityManager服务业务层接口,AMP类与AMS类都实现了IActivityManager接口方法,区别不同给的是AMS端显示了真正的具体服务,而AMP端是封装了相关的通信传输逻辑。AMP作为Binder通信的服务代理端,而AMS作为Binder通信的服务端实体,根据Android Binder框架实现之Java层Binder服务跨进程调用源码分析,AMP.bindService()最终调用AMS.startActivity(),整个流程图如下:

Android四大组件之Activity启动流程源码实现详解(一)
关于上述整个Binder IPC调用流程,可以使用如下伪代码来简述

AMP.startActivity(...)---> 
BinderProxy.transact(...) --->
BpBinder.transact(...)--->
binder驱动传输--->
JavaBBinder.onTransact(...)--->
AMN.onTransact(..)--->
AMN.startActivity(...)

2.5 AMP.startActivity(…)

	//ActivityManagerNative.java
    public int startActivity(IApplicationThread caller, 
    						 String callingPackage, 
    						 Intent intent,
            				 String resolvedType, 
            				 IBinder resultTo, 
            				 String resultWho, 
            				 int requestCode,
                             int startFlags, 
                             ProfilerInfo profilerInfo, 
                             Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        //写入AMS Binder服务描述信息即android.app.IActivityManager
        data.writeInterfaceToken(IActivityManager.descriptor);
        //写入IApplicationThread 匿名Binder服务实体(这个在attachApplication时写入过)
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
		//BinderProxy
		//mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,进而借助Binder驱动和AMS通信
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

这里如果对Binder框架熟悉的小伙们应该对上述的调用过程是见怪不怪了,但是有几个点我们需要注意:

  • 此处startActivity()的共有10个参数, 下面说说每个参数传递AMP.startActivity()每一项的对应值
参数类型 参数名称 参数含义以及取值
IApplicationThread caller 当前应用的ActivityThread对象ApplicationThread实例mAppThread
String callingPackage 调用当前ContextImpl.getBasePackageName(),获取当前Activity所在包名
Intent intent 启动目的端Activity传递过来的参数,其中携带目的端Acitivity隐式或者显示启动需要的参数
String resolvedType 调用intent.resolveTypeIfNeeded而获取
IBinder resultTo 参数类型也为IBinder实例,指向发起端Activity的ActivityRecord对象中的Token,其Binder实体在AMS中
String resultWho 来自于当前发起端Activity.mEmbeddedID,可能为null
int requestCode 启动目的端Activity的请求码,此时的取值为-1
int startFlags 此时取值为0,代指Activity的启动模式
ProfilerInfo profilerInfo 此时取值null,这个参数暂时没有搞懂是干啥的
Bundle options 启动目的端Activity附加参数,此时取值为null
  • startActivity中调用了二次Parcel类的方法writeStrongBinder(),这里我们需要注意writeStrongBinder()这二次写入的是Binder实体代理端还是代理端,是实名Binder还是匿名Binder。
  • 这里的mRemote指向BinderProxy,而BinderProxy持有C++端的BpBinder,而BpBinder作为远程Binder实体的通信代理端,最后借助Binder驱动和AMS通信,最后调用到ActivityManagerNative的onTransact()方法中


三. System_server进程接收启动Activity的请求

  通过上面的层层冲关,打怪我们跳出了发起端进程,来到了system_server进程,让我们接着分析看看system_server是怎么处理startActivity的RPC请求的。

3.1 AMN.onTransact

	//ActivityManagerNative.java
    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException {
        switch (code) {
        case START_ACTIVITY_TRANSACTION:
        {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
			//转换成ApplicationThread Binder实体代理端ApplicationThreadProxy
            IApplicationThread app = ApplicationThreadNative.asInterface(b);
            String callingPackage = data.readString();
            Intent intent = Intent.CREATOR.createFromParcel(data);
            String resolvedType = data.readString();
            IBinder resultTo = data.readStrongBinder();
            String resultWho = data.readString();
            int requestCode = data.readInt();
            int startFlags = data.readInt();
            ProfilerInfo profilerInfo = data.readInt() != 0
                    ? ProfilerInfo.CREATOR.createFromParcel(data) : null;
            Bundle options = data.readInt() != 0
                    ? Bundle.CREATOR.createFromParcel(data) : null;
			//调用AMN的子类AMS,详见章节3.2
            int result = startActivity(app, callingPackage, intent, resolvedType,
                    resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
            reply.writeNoException();
            reply.writeInt(result);
            return true;
        }

在正式开始上述的源码分析前,我们先来阐述一个重要的知识点,即在这个调用过程中涉及到两个进程,不妨令startActivity的发起进程记为进程Process_A,AMS Service所属进程记为进程Process_B;那么进程Process_A通过Binder机制(采用IActivityManager接口)向进程Process_B发起请求服务,进程Process_B则通过Binder机制(采用IApplicationThread接口)向进程Process_A发起请求服务。也就是说进程Process_A与进程Process_B能相互间主动发起请求,进而完成进程通信,但是这里有一点需要注意IApplicationThread的Binder实体端并没有注册到servicemanager进程中,它是一个依赖于实名Binder的匿名Binder。

这里涉及IApplicationThread很重要,它串联起了AMS对App进程的生命周期及其其它的控制,那么下面直接把其相关的类图展示如下:

Android四大组件之Activity启动流程源码实现详解(一)

这里的IApplicationThread与IActivityManager的Binder通信原理一样,ATP作为Binder通信的客户端,ATN作为Binder通信的服务端,其中ApplicationThread继承ATN类,覆写其中的部分方法。

接着继续分析onTransact方法,其根据AMP传递过来的code值进入START_ACTIVITY_TRANSACTION分支,然后解读取通过Binder驱动传递过来的数据,解析完成之后调用AMN的方法startActivity继续未完成之工作(这里的startActivity在AMS服务中具体实现),这里从驱动中获取到数据然后解析这里就不重点关注了。


3.2 AMS.startActivity

    @Override
    //AMS.java
    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());
    }
    final ActivityStackSupervisor mStackSupervisor;

    final ActivityStarter mActivityStarter;
    final ActiveServices mServices;
    @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) {
        enforceNotIsolatedCaller("startActivity");
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
                //这里的mActivityStarter是ActivityStarter的实例对象
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null);//详见章节3.3
    }

这里需要重点强调如下几点:

  • AMS是Android提供负责系统中四大组件的启动、切换、调度及应用进程的管理和调度等工作的Java层Binder服务,其身上的担子很重,为了减轻负担和代码逻辑的精简其会将重任委托给几个非常重要的类来执行ActivityStarter,ActivityStackSupervisor,ActiveServices,AMS的类图关系如下所示,并且关于每个类的作用详见博客Activity启动流程源码实现详解概要章节2.5这里就不重复了。
    Android四大组件之Activity启动流程源码实现详解(一)

  • 这里的mActivityStarter是ActivityStarter的实例对象,其是在AMS的构造方法中被创建的,如下所示可以看到其持有对AMS和ASS的引用。

//AMS.java
final ActivityStackSupervisor mStackSupervisor;
final ActivityStarter mActivityStarter;
final ActiveServices mServices;
public ActivityManagerService(Context systemContext) {
	...
	mServices = new ActiveServices(this);
	mStackSupervisor = new ActivityStackSupervisor(this);
    mActivityStarter = new ActivityStarter(this, mStackSupervisor);
	...
}

3.3 AS.startActivityMayWait

//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, 
            						IActivityManager.WaitResult outResult, 
            						Configuration config,
            						Bundle bOptions, 
            						boolean ignoreTargetSecurity, 
            						int userId,
            						IActivityContainer iContainer, 
            						TaskRecord inTask) {

  在正式开始分析该方法前,我们先对该方法的参数和入参整理一下,该方法的参数不少啊,总共有19个至多(不知道数对了没有啊),其参数类型和取值如下:

参数类型 参数名称 参数含义及取值
IApplicationThread caller 和发起端进程匿名Binder对象ActivityThread进行通信的代理端ATP
int callingUid 取值为-1,看参数命名应该是表示发起端的进程的uid
String callingPackage 发起端进程所在包名
Intent intent 启动目的端Activity传递过来的参数,其中携带目的端Acitivity隐式或者显示启动需要的参数
String resolvedType 发起端进程通过调用intent.resolveTypeIfNeeded而获取
IVoiceInteractionSession voiceSession 意义不明,取值为null
IVoiceInteractor voiceInteractor 意义不明,取值为null
IBinder resultTo 参数类型也为IBinder实例,指向发起端Activity的ActivityRecord对象中的Token,其Binder实体在AMS中
String resultWho 来自于当前发起端Activity.mEmbeddedID,可能为null
int requestCode 启动目的端Activity的请求码,此时的取值为-1
int startFlags 此时取值为0,代指Activity的启动模式
ProfilerInfo profilerInfo 此时取值null,这个参数暂时没有搞懂是干啥的
WaitResult outResult 此时取值为null,这个参数暂时没有搞懂是干啥的
Configuration config 应该是表示启动Activity的Configuration配置信息(不太确定),此时取值为null
Bundle options 启动目的端Activity附加参数,此时取值为null
boolean ignoreTargetSecurity 是否忽略检查发起端进程的安全,此时取值为false
int userId 通过mUserController.handleIncomingUser,当调用者userId跟当前处于同一个userId,则直接返回该userId;当不相等时则根据调用者userId来决定是否需要将callingUserId转换为mCurrentUserId
IActivityContainer iContainer 此时取值为null
TaskRecord inTask 此时取值为null

  入参分析完了,我们接着分析源码:

//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, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask) {
		...
        final Intent ephemeralIntent = new Intent(intent);
        //以传递进来的intent为参数重新创建新的Intent对象,即便intent被修改也不受影响
        intent = new Intent(intent);
        //收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity 
        ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);//重点分析该方法,详见章节3.4
        if (rInfo == null) {//不会进入该分支
        	...
        }
		//根据获取的rInfo信息重新组装intent和设置启动的参数信息
        ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);//详见3.5
        ...

        final ActivityStack stack;
        if (container == null || container.mStack.isOnHomeDisplay()) {//传入的参数container为null
            stack = mSupervisor.mFocusedStack;//进入该分支
        } else {
            stack = container.mStack;
        }
		//此时传入的config为null
        stack.mConfigWillChange = config != null && mService.mConfiguration.diff(config) != 0;
        ...
        if (aInfo != null &&
                (aInfo.applicationInfo.privateFlags
                        & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
            //hwavy-weight进程,貌似木有见过这个东东,暂时不管
        	...
        }
        ...
         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);//详见章节3.6

         Binder.restoreCallingIdentity(origId);
		...
		return res;        
}

该方法的主要功能如下:

  • 借助ASS的resolveIntent和resolveActivity方法,通过传递进来的参数(主要是intent)查找合适的目标Actitiy,并将保存到ActivityInfo中
  • 继续调用startActivityLocked方法,继续未完成启动工作

此时整个上述整个流程的伪代码如下:

	AMS.startActivity(...)
	 ActivityStarter.startActivityMayWait(...)
	   ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity
	     IPackageManager.Stub.resolveIntent(...)//通过PKMS实体查询
	   ActivityInfo aInfo = ASS.resolveActivity(...)根据获取的rInfo信息重新组装intent和设置启动的参数信息
	   ActivityStarter.startActivityLocked(...)

3.4 通过intent查询获取目的端Activity信息

  在正式开始该流程分析前,我们先来看看ResolveInfo,它是一个容器类,里面包含了ActivityInfo,ServiceInfo,ProviderInfo等成员来表示四大组件的信息,activity和broadcast信息都是用ActivityInfo来表示的。这三个成员只有一个不为空,这里我们启动的是activity,所以ActivityInfo是不为空的。ActivityInfo包含了各种各样的activity信息,都是声明在AndroidManifest.xml文件中的,比较重要的包括launchMode、theme、screenOrientation等,其中还包含了ApplicationInfo,提供packageName、targetSdkVersion等重要信息。关于这两者之间的关系,可以使用如下类图表示:
Android四大组件之Activity启动流程源码实现详解(一)

3.4.1 ASS.resolveIntent

//[ActivityStackSupervisor.java]
    ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId) {
        return resolveIntent(intent, resolvedType, userId, 0);
    }

    ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
        try {
        	//调用到同进程PKMS服务的resolveIntent
            return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
                    PackageManager.MATCH_DEFAULT_ONLY | flags
                    | ActivityManagerService.STOCK_PM_FLAGS, userId);//详见章节3.4.2
        } catch (RemoteException e) {
        }
        return null;
    }

  由于该流程牵涉到PKMS服务的调用,在开始源码前我们先看看PKMS的类图关系如下:
Android四大组件之Activity启动流程源码实现详解(一)

//[AppGlobals.java]
    public static IPackageManager getPackageManager() {
        return ActivityThread.getPackageManager();
    }

//[ActivityThread.java]
	static volatile IPackageManager sPackageManager;
    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            return sPackageManager;
        }
        //等同于IBinder b = new JavaBBinder()//此时AMS和PKMS在同一个进程,所以获取的是PKMS的Binder服务的实体端,不需要通过Binder IPC跨进程调用
        IBinder b = ServiceManager.getService("package");
        //等同于sPackageManager  = new IPackageManager.Stub(JavaBBinder)
        sPackageManager = IPackageManager.Stub.asInterface(b);
        return sPackageManager;
    }

  AppGlobals.getPackageManager()经过函数层层调用,获取的是IPackageManager.Stub,注意获取的是PKMS的实体端,所以无需经过Binder IPC调用,此处一定要特别注意!最终会像是用普通的类一样直接调用到PKMS对象.故此时调用方法为PMS.resolveIntent(),至于其中涉及的具体转换可以详见博客Android Binder框架实现之Java层Binder服务跨进程调用源码分析

3.4.2 PKMS.resolveIntent

  通过上述的分析,我们看到AMS解析Intent主要是通过PKMS来解析的,因为我们四大组件都是必须声明在AndroidManifest.xml文件中的(广播接收器允许动态注册)。Android这么做的原因主要是为了屏蔽进程间通讯细节,应用之间通过组件就可以交互,系统会在必要的时候拉起对方进程。但是这里会存在一个问题,即在应用没起来之前,只有PMS知道应用都有哪些组件,所以AMS必须借助PKMS来完成相关intent的查询。应用四大组件的信息在应用安装的时候,就已经被PMS解析保存起来了。如果没有声明在AndroidManifest.xml文件中,那么AMS就无法获取目标组件的信息,对于显式intent,会抛出错误;对于隐式intent,也会启动失败。关于PKSMS服务对App安装的处理不是本文的重点,这里不与过多分析。

//[PackageManagerService.java]
  @Override
  public ResolveInfo resolveIntent(Intent intent, String resolvedType,
          int flags, int userId) {
            enforceCrossUserPermission(Binder.getCallingUid(), userId,false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");

			//queryIntentActivitiesInternal方法返回的结果就是符合intent的ActivityInfo列表
            final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, userId);//详见章节3.4.3

	
			//根据priority,preferred选择最佳的Activity,当有多个合适的Actitiy的时候,会弹出选择框提供给用户进行选择
            final ResolveInfo bestChoice =
                    chooseBestActivity(intent, resolvedType, flags, query, userId);

            return bestChoice;
  }

3.4.3 PKMS.queryIntentActivitiesInternal

//[PackageManagerService.java]
	/*
	1.查看当前Intent是否是显式Intent。是则取出其中的class对象和AndroidManifest的进行匹配,匹配成功返回。
	2.如果没有指定包名则全系统的查找匹配intent
	3.如果指定包名,则从当前的包名寻找匹配规则相符合的intent的Activity
	*/
    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
            String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        flags = updateFlagsForResolve(flags, userId, intent);
        enforceCrossUserPermission(Binder.getCallingUid(), userId,
                false /* requireFullPermission */, false /* checkShell */,
                "query intent activities");
		//获取Intent的ComponentName
		ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
                comp = intent.getComponent();
            }
        }

		//不为空,则是通过显示Intent启动,直接获取到ActivityInfo返回
        if (comp != null) {
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
			//获取Activity信息
            final ActivityInfo ai = getActivityInfo(comp, flags, userId);
            if (ai != null) {
                final ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
            return list;
        }
        //comp为空,则是隐式启动
        synchronized (mPackages) {
            final String pkgName = intent.getPackage();
            if (pkgName == null) {//如果包名为空,则会通过ActivityIntentResolver等进行模糊匹配,比如根据Action、Category等
            	...
                return result;
            }
			// 通过包名获取到Package对象
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
                return filterIfNotSystemUser(
                        mActivities.queryIntentForPackage(
                                intent, resolvedType, flags, pkg.activities, userId),
                        userId);
            }
            return new ArrayList<ResolveInfo>();
        }
    }     

  上面的流程就是通过intent获取目的Activity的ResolveInfo核心代码,这里不过多展开了(因为牵涉到PKMS对App的安装解析流程),它的大致过程如下:

  • 首先获取Intent的Component对象,如果不为空,说明指定了Componet,那么就直接通过Componet找到ActivityInfo列表,并且这个列表size为1,所以这个ActivityInfo就是指定需要跳转的组件。
  • 如果没有指定Component,那就是隐式Intent调用,接着获取Intent传递的需要跳转的包名。
  • 如果包名为空,则会通过ActivityIntentResolver等进行模糊匹配,比如根据Action、Category等。
  • 如果包名不为空,则直接根据包名来获取到对应的ActivityInfo对象,而mActivities就是PMS存储的activity信息表。

3.4.4 通过intent查询获取目的端Activity信息小结

  至此通过intent查询获取目的端Activity信息就告一段落了,此时我们借助PKMS服务解析intent获取到了合适的ResolveInfo(启动包含了ActivityInfo信息),那么接下来就可以继续余下的工作了,我们还是用相关的伪代码来总结一下上述的流程:

   ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity
     IPackageManager.Stub.resolveIntent(...)//通过PKMS实体查询
	   PKMS.resolveIntent(...)
		 PKMS.queryIntentActivitiesInternal(...)
		 PKMS.chooseBestActivity(...)

3.5 ASS.resolveActivity

让我们整理下思路,回到章节3.3继续分析resolveActivity方法

//[ActivityStackSupervisor.java]
	/*根据获取的rInfo信息重新组装intent和设置启动的参数信息
	 startFlags = 0; 
	 profilerInfo = null; 
	 rInfo 指向通过PKMS解析intent信息获取到的ResolveInfo实例对象,其中包含ActivityInfo的信息
	*/
    ActivityInfo resolveActivity(Intent intent, ResolveInfo rInfo, int startFlags,
            ProfilerInfo profilerInfo) {
        final ActivityInfo aInfo = rInfo != null ? rInfo.activityInfo : null;
        if (aInfo != null) {
            intent.setComponent(new ComponentName(
                    aInfo.applicationInfo.packageName, aInfo.name));
            if (!aInfo.processName.equals("system")) {//对于非system进程,根据flags来设置相应的debug信息
                if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {//用于调试debug app
                    mService.setDebugApp(aInfo.processName, true, false);
                }

                if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {//调试native
                    mService.setNativeDebuggingAppLocked(aInfo.applicationInfo, aInfo.processName);
                }

                if ((startFlags & ActivityManager.START_FLAG_TRACK_ALLOCATION) != 0) {//用于调试allocation tracking
                    mService.setTrackAllocationApp(aInfo.applicationInfo, aInfo.processName);
                }

                if (profilerInfo != null) {
                    mService.setProfileApp(aInfo.applicationInfo, aInfo.processName, profilerInfo);
                }
            }
        }
        return aInfo;
    }

resolveActivity方法的处理逻辑比较简单,主要是根据前面获取的rInfo信息重新组装intent和设置Activity启动的参数信息。ActivityManager类提供了如下3个flags用于调试,如下:

  • START_FLAG_DEBUG:用于调试debug app
  • START_FLAG_NATIVE_DEBUGGING:用于调试native
  • START_FLAG_TRACK_ALLOCATION: 用于调试allocation tracking

3.6 AS.startActivityLocked

  让我们整理下思路,回到章节3.3继续分析startActivityLocked方法,在继续分析之前,我们还是整理整理system_server进程从接收到启动Activity至此startActivityLocked的调用流程!

	AMS.startActivity(...)
	 ActivityStarter.startActivityMayWait(...)
	   ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity
	     IPackageManager.Stub.resolveIntent(...)//通过PKMS实体查询
		   PKMS.resolveIntent(...)
			 PKMS.queryIntentActivitiesInternal(...)
			 PKMS.chooseBestActivity(...)
	   ActivityInfo aInfo = ASS.resolveActivity(...)根据获取的rInfo信息重新组装intent和设置启动的参数信息
	   ActivityStarter.startActivityLocked(...)

  不知道小伙们,我这个节奏是否还跟得上!如果小伙们感觉有点吃力了,不要退缩坚持就好了,因为当初的我也是这么过来的!大伙可以先上上厕所,喝杯茶。我们接着继续!

//[ActivityStarter.java]
    final int startActivityLocked(IApplicationThread caller, //caller是请求启动当前Activity的发起方,IApplicationThread类是AMS调用ActivityThread的IBinder接口,在启动者的ActivityThread中定义
			Intent intent, //启动当前Activity的intent
			Intent ephemeralIntent,//启动当前Activity的intent复本
            String resolvedType, //启动当前Activity的resolvedType
            ActivityInfo aInfo, //当前启动的Activity的ActivityInfo(PackageManger解析获得,具体获取见前面的操作步骤
            ResolveInfo rInfo,//目标Activity的ResolveInfo信息
            IVoiceInteractionSession voiceSession, //暂时忽略
            IVoiceInteractor voiceInteractor,//暂时忽略
            IBinder resultTo, // 调用方Activity的ActivityRecord,每个Activity在启动之后,AMS均会将这个Activity的ActivityRecord的IBinder再传递给Activity,作为其在AMS中的标识。
            String resultWho, 
            int requestCode, 
            int callingPid, int callingUid,//用于权限检查,检查请求放是否有权限启动这个Activity
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask) {
        int err = ActivityManager.START_SUCCESS;

		//用来存储调用者的进程记录对象
        ProcessRecord callerApp = null;
        if (caller != null) {
            callerApp = mService.getRecordForAppLocked(caller);//获取调用者的进程信息
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
				...
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }

        final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;



		//记录发起端Activity信息记录对象
        ActivityRecord sourceRecord = null;//表示请求启动当前Activity的Activity
        ActivityRecord resultRecord = null;//表示当前activity启动之后需要得到返回结果的activity
		
		/**若当前启动方式是以startActivityForResult启动的,
		*则保存在调用者Activity在sourceRecord中,
		*如果启动时候设置了requestCode并且大于是0,那么将接收
		*startActivityForResult返回值的Activity保存在resultRecord中。
		*在此种情况下,调用者和接收返回者的Activity是相同的
		*是不是还是很抽象,我们来举个例子:
		*假如Activity A通过startActivityForResult启动B,并且requestCode>0
		*那么此时sourceRecord和resultRecord都为A
		*/
		if (resultTo != null) {
			//获取调用者所在的Activity
            sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                    "Will send result to " + resultTo + " " + sourceRecord);
            if (sourceRecord != null) { //一般情况下,sourceRecord的activity使用startActivityForResult()启动当前activity且requestCode>=0,那么resultRecord = sourceRecord
                if (requestCode >= 0 && !sourceRecord.finishing) {
                    resultRecord = sourceRecord;
                }
            }
        }

        final int launchFlags = intent.getFlags();

		// Activity执行结果的返回由源Activity转换到新Activity, 不需要返回结果则不会进入该分支
		// 特殊情况,若sourceRecord启动当前activity时设置了标记Intent.FLAG_ACTIVITY_FORWARD_RESULT,且requestCode<0, 那么当前activity的resultRecord等于sourceRecord.resultTo,也就是sourceRecord的resultRecord
		
		/**
		 *FLAG_ACTIVITY_FORWARD_RESULT这个FLAG作用,举个例子:
		 * 当一个应用中存在有ActivityA,B,C,A以startActivityForResult方式启动了B,
		 * 此时B设置了FLAG_ACTIVITY_FORWARD_RESULT启动了C,注意此时B启动C
		 * 时requestCode不设置或者设置值要小于0,不然会报错。
		 * 那么原来在A中接收返回值从B返回的,但这时A接收的返回值变成从C返回。
		 */

		if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new
            // one being started, including any failures.
            // 将sourceRecord的resultRecord转移给当前新启动的activity
            if (requestCode >= 0) {
                ActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
				...
                callingPackage = sourceRecord.launchedFromPackage;
            }
        }

        if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
            //从Intent中无法找到相应的Component
            err = ActivityManager.START_INTENT_NOT_RESOLVED;
        }

        if (err == ActivityManager.START_SUCCESS && aInfo == null) {
            //从Intent中无法找到相应的ActivityInfo
            err = ActivityManager.START_CLASS_NOT_FOUND;
        }



		执行后resultStack = null
        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;

        if (err != START_SUCCESS) {
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(
                        -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
            }
            ActivityOptions.abort(options);
            return err;
        }

		//权限检测
        boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
                requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
                resultRecord, resultStack, options);
        abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
                callingPid, resolvedType, aInfo.applicationInfo);

        if (mService.mController != null) {
            try {
                Intent watchIntent = intent.cloneFilter();
                abort |= !mService.mController.activityStarting(watchIntent,
                        aInfo.applicationInfo.packageName);
            } catch (RemoteException e) {
                mService.mController = null;
            }
        }

		...
        if (abort) {//权限检查不满足,才进入该分支则直接返回
            if (resultRecord != null) {
                resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
                        RESULT_CANCELED, null);
            }

            ActivityOptions.abort(options);
            return START_SUCCESS;
        }

		...


		//创建Activity记录对象
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
                requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
                options, sourceRecord);//详见章节3.7
        if (outActivity != null) {
            outActivity[0] = r;// 将创建的ActivityRecord返回
        }

        if (r.appTimeTracker == null && sourceRecord != null) {
            // If the caller didn't specify an explicit time tracker, we want to continue
            // tracking under any it has.
            r.appTimeTracker = sourceRecord.appTimeTracker;
        }

		// 将mFocusedStack赋予当前stack,这里的mFocusedStack表示当前活动的
        final ActivityStack stack = mSupervisor.mFocusedStack;
        if (voiceSession == null && (stack.mResumedActivity == null
                || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
            // 前台stack还没有resume状态的Activity时, 则检查app切换是否允许    
            if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
                    realCallingPid, realCallingUid, "Activity start")) {
                PendingActivityLaunch pal =  new PendingActivityLaunch(r,
                        sourceRecord, startFlags, stack, callerApp);
				// 当不允许切换,则把要启动的Activity添加到mPendingActivityLaunches对象, 并且直接返回
                mPendingActivityLaunches.add(pal);
                ActivityOptions.abort(options);
                return ActivityManager.START_SWITCHES_CANCELED;
            }
        }

        if (mService.mDidAppSwitch) {
            //从上次禁止app切换以来,这是第二次允许app切换,因此将允许切换时间设置为0,则表示可以任意切换app
            mService.mAppSwitchesAllowedTime = 0;
        } else {
            mService.mDidAppSwitch = true;
        }

		//处理 pendind Activity的启动, 这些Activity是由于app switch禁用从而被hold的等待启动activity
        doPendingActivityLaunchesLocked(false);

        try {
			//这个方法很长,很长,很长
            err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
                    true, options, inTask);
        } finally {
            mService.mWindowManager.continueSurfaceLayout();
        }
        postStartActivityUncheckedProcessing(r, err, stack.mStackId, mSourceRecord, mTargetStack);
        return err;
    }

startActivityLocked方法看着代码一大堆,是有蛮唬人的。其实主要逻辑就是:

  • 进一步对发起端的进程做一些权限检查,然后接着确定sourceRecord和resultRecord的取值
  • 接着通过上述确认的参数构建ActivityRecord,这个是重点会在后面章节分析
  • 接着继续调用startActivityUnchecked方法开始后续的Activity启动,这个方法牵涉的逻辑很长,很长

3.7 ActivityRecord

  ActivityRecord是AMS中保存activity信息的数据结构,AMS就是通过着这样一个结构来管理Activity的,注意和ActivityInfo的区别!我个人认为二者最大的区别在与ActivityInfo是死的,它是对AndroidManifest.xml的完全解析的呈现,而ActivityRecord是根据发起端进程创建目标Activiyt传入的参数等情况确定的。

ActivityRecord类的定义如下:

//ActivityRecord 
final class ActivityRecord {                                      
	/*表示AMS在创建ActivityRecord时候指定*/
	final ActivityManagerService service; 
	
	/*这个是和WindomMangerService通信的,该值会赋值给Activity中*/
	final IApplicationToken.Stub appToken; 
	
	/*这个描述是AndroidManifest.xml中定义activity相关信息*/
	final ActivityInfo info; 
	
	/*这个描述是AndroidManifest.xml中定义application相关信息*/
	final ApplicationInfo appInfo; 
	
	...
	
	/*应用的包名*/
	final String packageName; 
	
	final String processName; 
	/**Activity亲和性,这上简单的描述就是该Activity应属于是哪个Task*/
	final String taskAffinity; 
	
	...
	/**以下三个表示该Activity类型*/               
	static final int APPLICATION_ACTIVITY_TYPE= 0;
	static final int HOME_ACTIVITY_TYPE = 1;
	static final int RECENTS_ACTIVITY_TYPE = 2;
	int mActivityType;
	...
	/**Activity属于哪个Task*/
	TaskRecord task;       
	/**通过startActivityForResult启动时,接收返回值的Activity*/
	ActivityRecord resultTo; 
	/**通过startActivityForResult启动时设置的requestCode*/
	final int requestCode;  
	...
	
	/*Activity所属的进程*/
	ProcessRecord app;      
	
	/*表示Activity的当前状态, INITIALIZING,RESUMED,PAUSING,PAUSED,STOPPING,STOPPED,FINISHING,DESTROYING,DESTROYED
	有这几种状态*/
	ActivityState state;   
	/*标记是否为Task的root Activity,比如每个应用有一个mainActivity,一般	
	*情况下该main Activity即为对应Task的rootActivity*/
	boolean frontOfTask;    
	
	/*标记该ActivityRecord是否已经stoped*/
	boolean stopped;        
	
	/*标记ActivityRecord是否已经finishing,这在activity finish时置为true*/
	boolean finishing;      
	
	boolean deferRelaunchUntilPaused;   
	                                  
	boolean visible;       
	boolean sleeping;       
	boolean nowVisible;    
	/*ActivityStack管理类*/
	final ActivityStackSupervisormStackSupervisor;

    ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
            int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
            ActivityInfo aInfo, Configuration _configuration,
            ActivityRecord _resultTo, String _resultWho, int _reqCode,
            boolean _componentSpecified, boolean _rootVoiceInteraction,
            ActivityStackSupervisor supervisor,
            ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
    	...
    	appToken = new Token(this, service);//注意此处的Token是一个匿名Binder,既然是Binder就可以跨进程传输了
    	state = ActivityState.INITIALIZING;
    	...
    }

我还得在2.3章节中对execStartActivity中传入的参数token吗,它的Binder实体就是在启动过程中经由此处创建的(当然它的Binder实体不是这里的Token,这里只是表达告诉各位小伙们这个token会随着Activity的创建会在AMS,WMS,Activity之间进行传递的)YOU

  有了以上知识的铺垫,那么此处的构造方法就很好理解了在AMS中为目标Activity构建了一个ActivityRecord数据结构,并且在其构造方法中实例化了一个Token,这个Token很重要它是Activity的唯一标识,并且会随着目标Activity的启动在AMS和WMS以及目标进程中传输!至此目标Ativity相关信息已经在AMS中建立了!
  这里补充一个小的知识点,我们可以借助dumpsys命令查看AMS中相关的ActivityRecord的数据结构信息,如下!特别是当我们想查看当前与用户交互的前台Activity时Android通过adb shell命令查看当前与用户交互的前台Activity

130|XXX:/ # dumpsys activity | grep ActivityRecord
        Hist #0: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}
        Run #0: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}
        Hist #0: ActivityRecord{68a76e3 u0 com.android.calculator2/.Calculator t77}
        Hist #0: ActivityRecord{697cb49 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t76}
        Hist #0: ActivityRecord{4c3e469 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t75}
        Hist #0: ActivityRecord{8a53d39 u0 com.pax.printtest/com.example.api.aidl.AidlActivity t74}
        Run #3: ActivityRecord{68a76e3 u0 com.android.calculator2/.Calculator t77}
        Run #2: ActivityRecord{697cb49 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t76}
        Run #1: ActivityRecord{4c3e469 u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t75}
        Run #0: ActivityRecord{8a53d39 u0 com.pax.printtest/com.example.api.aidl.AidlActivity t74}
  mFocusedActivity: ActivityRecord{4c7a084 u0 com.android.launcher3/.Launcher t73}


小结

阅读源码是很操蛋的事情,同样的如果将太多的逻辑放在一篇中我想小伙们也会阅读起来也会操蛋,失去耐心的的,所以本篇章就先到这里了。分析至此我们应该有了如下的知识图谱:

  • 发起端进程是怎么通过Instrumentation管理类,并且借助AMP完成启动Activity请求的发送
  • system_server进程中的AMS初步处理启动Activiyt的请求,并借助PKMS服务解析intent获取目标Activity的ActivityInfo信息,然后通过上述解析得到的数据为目标Activiyt构建ActivityRecord数据结构

关于上述整个的过程可以使用下述的伪代码来简单描述:

发起端进程发起启动Activity请求
	Activity.startActivity(...)
	  Activity.startActivityForResult(...)
	    mInstrumentation.execStartActivity(...)
		  AMP.startActivity(...)//通过AMS代理端向AMS发起启动Activity的Binder IPC请求
		  mInstrumentation.checkStartActivityResult(...)//检测启动是否成功
		mMainThread.sendActivityResult(...)



system_server进程端
AMS解析Intent	  
	AMS.startActivity(...)
	 ActivityStarter.startActivityMayWait(...)
	   ResolveInfo rInfo = ASS.resolveIntent(...)//收集Intent所指向的Activity信息, 当存在多个可供选择的Activity,则直接向用户弹出resolveActivity
	     IPackageManager.Stub.resolveIntent(...)//通过PKMS实体查询
		   PKMS.resolveIntent(...)
			 PKMS.queryIntentActivitiesInternal(...)
			 PKMS.chooseBestActivity(...)
	   ActivityInfo aInfo = ASS.resolveActivity(...)根据获取的rInfo信息重新组装intent和设置启动的参数信息
	   ActivityStarter.startActivityLocked(...)
		  ActivityRecord r = new ActivityRecord(callerApp,intent,aInfo,mSupervisor,...)
			appToken = new Token(this, _intent);
			  设置state为INITIALIZING
		  ActivityStarter.startActivityUnchecked(...)  
	   
创建目的端Activity的ActivityRecord
	ActivityStarter.startActivityLocked(...)
	  ActivityRecord r = new ActivityRecord(callerApp,intent,aInfo,mSupervisor,...)
	    appToken = new Token(this, _intent);
		  设置state为INITIALIZING
		

好了,今天的博客就到这里了!阅读源码小伙们一定要做好心理准备,千万不能半途而废!在接下来的篇章中我们将继续分析system_server进程对Activity启动的请求处理,希望小伙们能继续关注。

本文地址:https://blog.csdn.net/tkwxty/article/details/108680198