精华内容
下载资源
问答
  • Activity启动流程源码分析

    1、前述

    在上一篇文章中我们已经详细的阐述了通过Launcher图标启动Activity的流程Activity启动流程源码分析之Launcher启动(二)。由于是第一次创建Activity,所以会新创建进程,而在Activity启动流程源码分析之入门(一)文章中我们也说了,Activity的启动方式有两种,另外一种就是我们今天要说的startActivity启动方法。

    好啦,话不多说,我们直接进入今天的主题,首先我们来看一下时序图。

    2、Activity启动流程时序图

    Activity启动流程时序图

    与之前的Launcher启动方式相比,这里主要就是缺少了启动新进程的步骤,所以接下来我们重点展示两种启动方式的不同点。

    3、启动流程说明

    说明:由于本篇博客大部分步骤和Activity启动流程源码分析之Launcher启动(二)相同,所以在此只展示不同点,相同的步骤请参考之前的文章。

    (1)应用程序的入口是从Activity.startActivity()开始的。

    (2)上一篇文章的(26)步骤ActivityStackSupervisor.startSpecificActivityLocked()方法执行不同。

    void startSpecificActivityLocked(ActivityRecord r,
                boolean andResume, boolean checkConfig) {
            // Is this activity's application already running?
            ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                    r.info.applicationInfo.uid, true);
    
            r.task.stack.setLaunchTime(r);
    
            //app对象不为null,所以if条件成立,进入条件后执行realStartActivityLocked方法,并且直接return
            if (app != null && app.thread != null) {
                try {
                    //......
                    realStartActivityLocked(r, app, andResume, checkConfig);
                    return;
                } catch (RemoteException e) {
                   //......
                }
            }
    
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }

    由于这里不是第一次启动Activity,所以通过mService.getProcessRecordLocked()方法取回的app对象不为null,所以这里直接进入realStartActivityLocked方法,不会执行startProcessLocked方法,所以这里不需要创建新的进程。

    (3)ActivityStackSupervisor.realStartActivityLocked()

    直接执行到realStartActivityLocked的方法,这一步与上一篇文章的(32)步相同,以下步骤和上一篇相同。

    这样,应用程序内部的Activity就被启动起来了,我们回顾一下与Launcher启动方式的不同点在哪里?

    1. 首先就是启动开始的位置不同,Launcher是从Launcher.startActivitySafely()方法开始启动的,而Activity是从Activity.startActivity()方法开始的。

    2. 当执行到上一篇文章的(26)步骤ActivityStackSupervisor.startSpecificActivityLocked()方法时,Launcher方式会选择创建新的进程,进入ActivityManagerService.startProcessLocked()方法,而Activity内部启动的Activity是进入ActivityStackSupervisor.realStartActivityLocked()方法。

    好啦,接下来我们和之前一样将上面的流程总结一下。

    4、总结

    由于和前一篇博客的内容差不多,所以这里就不做详细的步骤介绍了,唯一的区别就是在Activity内部启动Activity时无需启动新的进程。

    好啦,到此整个Activity的启动流程我们分三篇博客也就说完啦!在此勉励一下自己再接再厉,加油!

    展开全文
  • Activity启动流程(一)发起端进程请求启动目标Activity

    千次阅读 热门讨论 2020-09-22 17:30:05
       Android四大组件之Activity启动流程源码实现详解(一) Activity启动流程源码实现详解系列博客目录: Activity启动流程源码实现详解概要 前言   在正式开始Android四大组件之Activity启动流程源码实现详解...

              发起端进程请求启动目标Activity


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

    Android应用进程创建流程大揭秘
    [Android四大组件之bindService源码实现详解
    Android四大组件之Activity启动流程源码实现详解概要
    Activity启动流程(一)发起端进程请求启动目标Activity
    Activity启动流程(二)system_server进程处理启动Activity请求
    Activity启动流程(三)-Activity Task调度算法复盘分析
    Activity启动流程(四)-Pause前台显示Activity,Resume目标Activity
    Activity启动流程(五)请求并创建目标Activity进程
    Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application
    Activity启动流程(七)初始化目标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流程在这里插入图片描述

    • 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(),整个流程图如下:

    在这里插入图片描述
    关于上述整个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进程的生命周期及其其它的控制,那么下面直接把其相关的类图展示如下:

    在这里插入图片描述

    这里的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这里就不重复了。
      在这里插入图片描述

    • 这里的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 指定待启动Activity所在的任务,此时取值为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等重要信息。关于这两者之间的关系,可以使用如下类图表示:
    在这里插入图片描述

    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的类图关系如下:
    在这里插入图片描述

    //[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;
      }
    

    并且上述如果是通过隐式方式启动,假如存在多个合适的Actitiy的时候,会弹出选择框提供给用户进行选择,如下所示:
    在这里插入图片描述

    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,//启动Activity的flag
                ActivityOptions options, 
                boolean ignoreTargetSecurity, //
                boolean componentSpecified,
                ActivityRecord[] outActivity, //输出参数,记录要启动的Actiivty的ActivityRecord信息
                ActivityStackSupervisor.ActivityContainer container,
                TaskRecord inTask) //指定待启动的Activity的任务栈,此处为null
       {
            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) {
                //存在冲突,则返回异常
                if (requestCode >= 0) {
                    ActivityOptions.abort(options);
                    return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
                }
                // 将sourceRecord的resultRecord转移给当前新启动的activity
                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) {
                	// 此处,如果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);
                // 如果权限检查失败,会中断Activity的启动过程,但返回的却是START_SUCCESS
                //这个地方很奇怪啊
                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) {
                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;
            }
    
    		//在创建ActivityRecord之后,也有一些处理,包括AppSwitch,优先启动之前被阻塞的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方法看着代码一大堆,是有蛮唬人的!特别是如此多的入参参数,入参参数多那么就意味着变数多,需要考虑的场景也比较多。假如我们站在上帝的视角出发,从一个Activity启动另外一个Activity,这其中牵涉到了很多譬如安全检测,任务栈,Stack栈的调度等等,所以才会有这么多参数入参。
    那么该方法的主要逻辑就是什么呢,如下:

    • 进一步对发起端的进程做一些权限检查,然后接着确定sourceRecord和resultRecord的取值
    • 接着通过上述确认的参数构建ActivityRecord,这个是重点会在后面章节分析
    • 在创建ActivityRecord之后,也有一些处理,包括AppSwitch,优先启动之前被阻塞的Activity,然后,进入了Activity过程的下一阶段startActivityUnchecked(…),从该方法名可以看出,该做的检查已经做完了,剩下的函数调用就不需要进行额外的检查了(Unchecked),这个在分析Android源码中经常会看到类似的命名规则。
    • 接着继续调用startActivityUnchecked方法开始后续的Activity启动,这个方法牵涉的逻辑很长,很长,并且从该方法命名可以看出,该做的检查已经做完了,剩下的函数调用就不需要进行额外的检查了(Unchecked)。

    并且这里我们注意到startActivityLocked方法是携带有返回值,我们来看看该方法可能的返回值(此时的我是站在上帝的视角)(这些返回值定义在ActivityManager.java中)。

    返回值定义 返回值含义
    START_SUCCESS(0) 启动成功
    START_INTENT_NOT_RESOLVED(-1) 无法解析Intent所请求的Activity
    START_CLASS_NOT_FOUND(-2) 无法找到目标Activity的类
    START_FORWARD_AND_REQUEST_CONFLICT(-3) 带RequestCode启动Activity时,存在的一种与resultTo冲突的场景
    START_PERMISSION_DENIED(-4) 调用者没有获取启动Activity的授权
    START_NOT_VOICE_COMPATIBLE(-7) 当前并不支持语音
    START_NOT_CURRENT_USER_ACTIVITY(-8) 目标Activity并非对当前用户可见
    START_SWITCHES_CANCELED(4) App Switch功能关闭时,需要将待启动的Activity推入Pending状态

    上述可以看出,小于零的返回值,表示启动失败;大于等于零的返回值,表示启动成功,通过一些大于零的整数来区分不同的启动场景。还有一些返回值没有在这里列出,因为还依赖于后续方法startActivityUnchecked调用的返回值。

    上述咔咔的一顿分析完startActivityLocked,想必想速成的小伙们内心是崩溃的,如此复杂的判定,竟然还只是创建了一个ActivityRecord!如果小伙们没有强大的学习动力和毅力,估计接下来的分析,只会更加崩溃和迷惘蛋疼,越往后的处理逻辑就越复杂特别是在任务栈和stack相关的调度中。吃得苦中苦方为人上人啊,所以阅读源码不是一蹴而就的是一个日积月累的过程,越是不懂越是需要迎难而上,多吃重复总会啃下这些硬骨头的。


    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之间进行传递的

      有了以上知识的铺垫,那么此处的构造方法就很好理解了在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.xxx.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.xxx.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启动的请求处理,希望小伙们能继续关注Activity启动流程(二)system_server进程处理启动Activity请求

    展开全文
  • 深入Activity,Activity启动模式LaunchMode完全解析 在平时的开发中,我们可能会了解到Activity的任务栈还有Activity的启动模式。那么Activity的启动模式都分别是怎么样的呢?如果设置了这些启动模式对任务栈有事么...

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/53221384
    本文出自【DylanAndroid的博客】


    深入Activity,Activity启动模式LaunchMode完全解析

    在平时的开发中,我们可能会了解到Activity的任务栈还有Activity的启动模式。那么Activity的启动模式都分别是怎么样的呢?如果设置了这些启动模式对任务栈有事么影响
    ,还有就是这么启动模式在实际的开发中有什么应用呢?这里用图例和demo来分析一下Activity的启动模式。

    Demo图
    device.png?raw=true

    1.Standard:标准启动模式

    Activity的默认模式,所有的Activity元素遵循先进后出的进栈出栈的特性,这种的比较简单

    启动顺序:A->B->C

    回退顺序:C->B->A.

    Standard

    2.SingleTop:栈顶复用模式

    栈顶复用模式,如果想要打开的activity在任务栈的栈顶已经存在,就不会创重新建新的实例,而是调用该Activity的 onNewIntent() 方法。避免栈顶的activity被重复的创建。

    例如A.B启动模式为Standard,C启动模式为SingleTop

    启动顺序:A->B->C—>C

    回退顺序:C->B->A.而不是C->C->B->A

    SingleTop
    应用如下:
    * 点击通知栏重复打开Activity的问题
    全新的Android通知栏,已抛弃setLatestEventInfo,兼容高版本 这篇文章里面
    我们打开一个通知栏,点击通知栏默认打开MainActivity,有一个问题,就是如果不设置MainActivity的launchMode,就会每次点击通知栏的时候会重新打开一个Activity。
    我们可以将MainActivity的启动模式设置为SingleInstance,就不会再重新打开MainActivity,而是调用MainActivity的onNewIntent() 方法。
    * 可以解决按钮重复点击的问题(当然这种启动模式不是为了去解决这个问题在这里这是说为了用这么应用去说明SingleTop启动模式)。

    3.SingleTask:栈内复用模式

    如果想要启动的Activity在当前栈内启动之后,该activity只会在任务栈里面存在一个实例。如果要再次打开这个activity,在任务栈里面如果已经存在,就不会创建新的activity,
    而是复用栈内的这个已经存在的activity,调用改Activity的 onNewIntent() 方法,并且清空这个activity任务栈上面所有的activity。

    例如A.C.D启动模式为Standard,B启动模式为SingleTask

    启动顺序:A->B->C—>D—>B

    回退顺序:B->A.而不是B—>D->C->B->A

    SingleTop
    应用如下:如果从主页去登录,然后去注册,注册完成如果直接回去主页,可以将主页的launchMode设置为SingleTask。直接从注册跳到主页即可,不用去关心LoginActivity是否关闭,还是什么时候关闭。

    4.SingleInstance:单一实例模式

    在整个Android系统中(可能会有很多任务栈)里面只有一个实例存在。不同的应用程序app去启动这个activity,就会共享公用同一个activity。
    他会运行在自己单独的的任务栈里面,并且这个单独的任务栈里面只会存在着一个实例。而且这个单独的任务栈会在最底层。
    应用场景:系统的发短信,打电话,来电,浏览器等。这种模式在平时很少去使用,一般在Launcher中可能会用到。

    例如A.C启动模式为Standard,B启动模式为SingleInstance

    启动顺序:A->B->C;注意:此时产生了两个任务栈,B产生了一个新的任务栈,并处于其他任务栈的下面。

    回退顺序:C->A->B.而不是C->B->A

    SingleTop

    5.GitHub

    展开全文
  •       Activity启动流程源码实现详解(二) Android四大组件源码实现详解系列博客目录: Android应用进程创建流程大揭秘 Android四大组件之bindService源码实现详解 Android四大组件之Activity启动流程源码实现...

            system_server进程处理启动Activity请求


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

    Android应用进程创建流程大揭秘
    [Android四大组件之bindService源码实现详解
    Android四大组件之Activity启动流程源码实现详解概要
    Activity启动流程(一)发起端进程请求启动目标Activity
    Activity启动流程(二)system_server进程处理启动Activity请求
    Activity启动流程(三)-Activity Task调度算法复盘分析
    Activity启动流程(四)-Pause前台显示Activity,Resume目标Activity
    Activity启动流程(五)请求并创建目标Activity进程
    Activity启动流程(六)注册目标Activity进程到system_server进程以及创建目标Activity进程Application
    Activity启动流程(七)初始化目标Activity并执行相关生命周期流程



    引言

      还记得大明湖畔的夏雨荷吗!错了,还记得我们前面章节博客Android四大组件之Activity启动流程源码实现详解(一)吗,在上述博客中我们重点分析了Activity启动的如下相关知识点:

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

    那么在本篇博客中我们将继续分析system_server对Activity启动请求的处理流程:

    • system_server进程通过AMS处理启动Activity请求
      4.为目标Activity查找/分配或者创建最优Task栈以及ActivityStack栈
      5.Pause前台Activity
      6.Resume请求的目标Activity
      7.AMS请求zygote进程为目标Activity创建所属进程

    • 注意:本篇的介绍是基于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/content/pm/
    --- ActivityInfo.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

    在正式开始今天博客相关源码分析前,还是先奉上调用的时序图以便小伙们先从整体上有个清晰的概括,然后再从细节开撸!

    在这里插入图片描述



    一.前期知识准备

      说实话,此处章节是我在将第二大章节写了一大半情况下回过头来撰写的,因为如果这里不将此处的知识点阐述清楚的话,感觉后面的章节没有办法进行!还记得我们在前面博客Android四大组件之Activity启动流程源码实现详解概要的章节2.7中我们分析了ActivityRecord、TaskRecord、ActivityStack、ProcessRecord、ActivityStackSupervisor在整个Activity启动的中的关系视图,但是该示意图是从整个AMS框架来说的,并且也只是介绍了一个大概。
    在这里插入图片描述

    今天我们先抛开AMS的整体不谈,先谈谈ActivityRecord、TaskRecord、ActivityStack这三个类之间的关联,因为本篇的源码分析将会重点涉及到这三者,所以要先弄明白几个重要的类及概念(ActivityRecord在前面的博客Android四大组件之Activity启动流程源码实现详解(一)已经有分析过了),所以在正式源码前我们先来看看另外两者!
    在这里插入图片描述


    1.1 TaskRecord

      TaskRecord是用来管理ActivityRecord的容器数据结构,用于记录该任务栈的activity开启的先后顺序,而TaskRecord对这些ActivityRecord的管理是以栈的形式来管理的,既然是栈那就肯定满足后进先出的原则!TaskRecord管理的ActivityRecord不一定都属于同一个App进程,这个需要根据实际情况来判定(这个从我们的最上面的示意图也可以看到)!

    //[TaskRecord.java]
    final class TaskRecord {
    	final int taskId;       // 任务ID
        String affinity;        // 是指root activity的affinity,即该Task中第一个Activity
        String rootAffinity;    // 
    	Intent intent;          // 最开始创建该Task的intent
    
    	int userId;             // 记录创建该Task的用户id
    
        
        final ArrayList<ActivityRecord> mActivities;//使用一个ArrayList来保存所有的管理的ActivityRecord
    
        String mCallingPackage;//调用者包名
        ActivityStack stack;//TaskRecord所在的ActivityStack,管理者这个task中的Activity
    	final ActivityManagerService mService;//AMS的
    
    	//添加Activity到Task栈顶部
        void addActivityToTop(ActivityRecord r) {
            addActivityAtIndex(mActivities.size(), r);
        }
    
    	//添加Activity到指定的索引位置
        void addActivityAtIndex(int index, ActivityRecord r) {
        	...
        }
    
    	//获取根ActivityRecord的intent信息
        Intent getBaseIntent() {
            return intent != null ? intent : affinityIntent;
        }
        
        //获取根ActivityRecord,即Task栈底的ActivityRecord(因为它是后进先出)
        ActivityRecord getRootActivity() {
            for (int i = 0; i < mActivities.size(); i++) {
                final ActivityRecord r = mActivities.get(i);
                if (r.finishing) {
                    continue;
                }
                return r;
            }
            return null;
        }
    	//获取栈顶ActivityRecord
        ActivityRecord getTopActivity() {
            for (int i = mActivities.size() - 1; i >= 0; --i) {
                final ActivityRecord r = mActivities.get(i);
                if (r.finishing) {
                    continue;
                }
                return r;
            }
            return null;
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder(128);
            if (stringName != null) {
                sb.append(stringName);
                sb.append(" U=");
                sb.append(userId);
                sb.append(" StackId=");
                sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
                sb.append(" sz=");
                sb.append(mActivities.size());
                sb.append('}');
                return sb.toString();
            }
            sb.append("TaskRecord{");
            sb.append(Integer.toHexString(System.identityHashCode(this)));
            sb.append(" #");
            sb.append(taskId);
            if (affinity != null) {
                sb.append(" A=");
                sb.append(affinity);
            } else if (intent != null) {
                sb.append(" I=");
                sb.append(intent.getComponent().flattenToShortString());
            } else if (affinityIntent != null) {
                sb.append(" aI=");
                sb.append(affinityIntent.getComponent().flattenToShortString());
            } else {
                sb.append(" ??");
            }
            stringName = sb.toString();
            return toString();
        }
    }
    

    有了前面的分析,我们来实际看看TaskRecord的数据情况,而恰好Android为我们提供了一个很好的命令dumpsy可以让我们洞察一切,通过dump可以看到此时存在有八个TaskRecord!

    XXX:/ # dumpsys activity | grep TaskRecord
      * Recent #0: TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
      * Recent #1: TaskRecord{c6a6d0b #1 I=com.android.settings/.FallbackHome U=0 StackId=-1 sz=0}
      * Recent #2: TaskRecord{80bf7e8 #79 A=com.android.settings U=0 StackId=-1 sz=0}
      * Recent #3: TaskRecord{8116e01 #77 A=com.android.calculator2 U=0 StackId=-1 sz=0}
      * Recent #4: TaskRecord{4b654a6 #76 A=com.cyanogenmod.filemanager U=0 StackId=-1 sz=0}
      * Recent #5: TaskRecord{dd0cee7 #75 A=org.codeaurora.gallery U=0 StackId=-1 sz=0}
      * Recent #6: TaskRecord{e9caa94 #74 A=com.xxx.printtest U=0 StackId=-1 sz=0}
      * Recent #7: TaskRecord{725e93d #44 I=com.android.settings/.Settings$DataUsageSummaryActivity U=0 StackId=-1 sz=0}
          TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
          TaskRecord{b80c4da #80 A=com.android.launcher3 U=0 StackId=0 sz=1}
    

    1.2 ActivityStack

      如果说TaskRecord是ActivityRecord的大管家,那么ActivityStack则是TaskRecord大管家,即ActivityStack是用来管理TaskRecord一种结构容器。ActivityStack也是我们通常意义上所说的Activity栈,它存在如下的几种的StackId(即我们可以把ActivityStack归纳为几种情况),这个也可以通过前面1.1章节最后的打印看出来!

    //【ActivityManager.java StackId]
        public static class StackId {
    
            public static final int INVALID_STACK_ID = -1;//非法stack ID.
            public static final int FIRST_STATIC_STACK_ID = 0;
            
            //Launcher的Activity以及recentsAPP
            public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
            
            //正常启动Activity的所处的ActivityStack
            public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
            
            public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
            public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;//这个是分屏应用所处于的ActivityStack
            public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;//画中画模式   
            public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;  
            public static final int FIRST_DYNAMIC_STACK_ID = LAST_STATIC_STACK_ID + 1;
    }
    

    接着继续分析,ActivityStack是管理系统中所有Activity状态的一个数据结构!把我的意大利炮拿出来朝着它狠狠的开炮!

    //[ActivityStack.java]
    final class ActivityStack {
             ...
             
             //Activity状态值,和Activity生命周期对应
        enum ActivityState {
    		INITIALIZING,//正在初始化
    	    RESUMED,//恢复
    	    PAUSING,//正在暂停
    	    PAUSED,//已经暂停
    	    STOPPING,//正在停止
    	    STOPPED,//已经停止
    	    FINISHING,//正在完成
    	    DESTROYING,//正在销毁
    	    DESTROYED//已经销毁
        }
        
     	...
        final ActivityManagerService mService;//AMS服务的引用
        final WindowManagerService mWindowManager;//WMS服务的引用
    
     
    	//使用一个ArrayList来保存TaskRecord,包括所有前面Activity的回退记录,包括可能正在运行的Activity
        private final ArrayList<TaskRecord>mTaskHistory = new ArrayList<>();
     
     	//该Stack中正在pause的ActivityRecord
    	ActivityRecord mPausingActivity = null;
    
    	//个表示当前ActivityStack处于已经resumed的activity
        ActivityRecord mResumedActivity = null;
     
    
        //表示该Stack中最后被paused过程的activity
        ActivityRecord mLastPausedActivity = null;
     
    	//最近一次被启动的Activity
        ActivityRecord mLastStartedActivity = null;
     
        final int mStackId;//该Stack的身份ID
         
         ...
        //在每个ActivityStack中保存着一份所有的ActivityStack
        ArrayList<ActivityStack> mStacks;
        
        int mDisplayId;
     
        
        //管理ActivityStack的的ASS的引用
        final ActivityStackSupervisor mStackSupervisor;
    
    	//创建TakRecord,这个会在后面的博客中调用到
        TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
                IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
                boolean toTop) {
    
    		//创建一个task
            TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
                    voiceInteractor);
            // add the task to stack first, mTaskPositioner might need the stack association
    		//将task添加到ActivityStack中去
    		addTask(task, toTop, "createTaskRecord");
            final boolean isLockscreenShown = mService.mLockScreenShown == LOCK_SCREEN_SHOWN;
            if (!layoutTaskInStack(task, info.windowLayout) && mBounds != null && task.isResizeable()
                    && !isLockscreenShown) {
                task.updateOverrideConfiguration(mBounds);
            }
            return task;
        }
    	//添加TaskRecord
        void addTask(final TaskRecord task, final boolean toTop, String reason) {
            final ActivityStack prevStack = preAddTask(task, reason, toTop);
    
            task.stack = this;
            if (toTop) {
                insertTaskAtTop(task, null);
            } else {
                mTaskHistory.add(0, task);
                updateTaskMovement(task, false);
            }
            postAddTask(task, prevStack);
        }
        @Override
        public String toString() {
            return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
                    + " stackId=" + mStackId + ", " + mTaskHistory.size() + " tasks}";
        }
        ..
    }
    

      通过前面的源码我们可以看到ActivityStack使用了一个ArrayList来保存TaskRecord,另外,ActivityStack中还持有ActivityStackSupervisor对象的引用,这个是用来管理ActivityStacks的这里就不过多介绍了,章节1.3会简单介绍一下,后面会开辟一个专门的章节来分析这块!

    有了前面的分析,我们来实际看看ActivityStack的数据情况,而恰好Android为我们提供了一个很好的命令dumpsy可以让我们洞察一切,通过dump可以看到此时存在一个ActivityStack!

    XXX:/ # dumpsys activity | grep ActivityStack
      mFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks} mLastFocusedStack=ActivityStack{55a06c8 stackId=1, 5 tasks}
    

    1.3 ActivityStackSupervisor

      如果说ActivityStack则是TaskRecord大管家,那么ActivityStackSupervisor则是ActivityStack大管家,即ActivityStackSupervisor是用来管理ActivityStack一种结构容器。

    public final class ActivityStackSupervisor implements DisplayListener {
    	...
    	final ActivityManagerService mService;//AMS 实例对象的引用
    	private RecentTasks mRecentTasks;//管理RecentTasks 
    	int mCurrentUser;//当前用户
    	ActivityStack mHomeStack;//Home所属Stack
    	ActivityStack mFocusedStack;//当前持有焦点的Stack
    	private ActivityStack mLastFocusedStack;//最后获取焦点的stack,此时表示正在切换
    	//ActivityDisplay列表,以当前的displayid为key这个可以对应多种显示设备,我们这里只考虑一种),以ActivityDisplay为value
    	private final SparseArray<ActivityDisplay> mActivityDisplays = new SparseArray<>();
    	private SparseArray<ActivityContainer> mActivityContainers = new SparseArray<>();//以mStackId为key
    
    
    
        class ActivityDisplay {
            int mDisplayId;
            Display mDisplay;
            DisplayInfo mDisplayInfo = new DisplayInfo();
    
    
            final ArrayList<ActivityStack> mStacks = new ArrayList<>();
    
            ActivityRecord mVisibleBehindActivity;
    
            ActivityDisplay() {
            }
            ...
        }
    	...
    }
    

    这里我们重点关注一下mHomeStack和mFocusedStack以及mLastFocusedStack,并且mActivityDisplays是通过displayid来区分当前显示的ActivityStack的。


    1.4 Activity各种栈关系总结

    在这里插入图片描述
    有了前面知识的铺垫,我们这里对AMS中牵涉的各种栈结构体的组成关系来简单总结一下:

    • 在不考虑分屏和虚拟屏的情况下,我们认为ActivityStackSupervisor与ActivityDisplay都是系统唯一,如果考虑起来就复杂了
    • 每个ActivityStack中可以有若干个TaskRecord对象,它有一个ArrayList类型的成员mTaskHistory,用于存储TaskRecord
    • 每个TaskRecord包含如果若干个ActivityRecord对象,这就是我们常说的任务栈,具有后进先出的特点
    • 每个ActivityRecord记录一个Activity信息,并且每个ActivityRecord会对应到一个TaskRecord,ActivityRecord中类型为TaskRecord的成员task,记录所属的Task,这里有一点需要注意的是Activity和ActivityRecord并不是一对一的,而是一对多,因为一个Actitiy可能存在多个启动方式进而导致存在多个ActivityRecord
    • ActivityStackSupervisor,负责所有Activity栈的管理。内部管理了mHomeStack、mFocusedStack和mLastFocusedStack三个Activity栈。其中,mHomeStack管理的是Launcher相关的Activity栈;mFocusedStack管理的是当前显示在前台Activity的Activity栈;mLastFocusedStack管理的是上一次显示在前台Activity的Activity栈
    • ActivityDisplay牵涉到Android设备的多屏显示,通常每个ActivityDisplay主要有Home Stack和App Stack这两个栈

    上述几个之间的管理非常紧凑,可以通过正向链表和反向链表通过其中的一个点切入获取到其它对应的关联的结构,这个从后续分析的查找复用ActivityRecord和Task以及Stack可以看出来

    • 正向关系链表
    ActivityStackSupervisor.mActivityDisplays
    ---> ActivityDisplay.mStacks
    ---> ActivityStack.mTaskHistory
    ---> TaskRecord.mActivities
    ---> ActivityRecord
    
    • 反向关系链表
    ActivityRecord.task
    ---> TaskRecord.stack
    ---> ActivityStack.mStackSupervisor
    ---> ActivityStackSupervisor
    

    关于上述之间的关联,小伙们可以使用命令dumpsys activity activities进行查看,虽然这里将贴出来会显得很啰嗦,但是为了小伙们的学习我这里也是拼了,因为这样会更加的清晰明了!

    ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
    Display #0 (activities from top to bottom)://测试终端只存在一个显示设备,所以Displayid只会存在一个
      Stack #1://当前焦点的ActivtyStack id
      mFullscreen=true
      mBounds=null
        Task id #96//当前获取焦点的Task任务栈id
        mFullscreen=true
        mBounds=null
        mMinWidth=-1
        mMinHeight=-1
        mLastNonFullscreenBounds=null
        * TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}//Task任务栈具体信息
          userId=0 effectiveUid=u0a21 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
          affinity=com.cyanogenmod.filemanager
          intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity}//启动目标Activity的intent信息
          realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
          autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
          rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
          Activities=[ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}]//当前获取焦点的Activity的ActivityRecord信息
          askedCompatMode=false inRecents=true isAvailable=true
          lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/96_task_thumbnail.png
          stackId=1
          hasBeenVisible=true mResizeMode=RESIZE_MODE_UNRESIZEABLE isResizeable=false firstActiveTime=1601263245356 lastActiveTime=1601263245356 (inactive for 38s)
          * Hist #0: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
              packageName=com.cyanogenmod.filemanager processName=com.cyanogenmod.filemanager
              launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
              app=ProcessRecord{1544be3 8312:com.cyanogenmod.filemanager/u0a21}
              Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.cyanogenmod.filemanager/.activities.NavigationActivity bnds=[536,168][712,356] }
              frontOfTask=true task=TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
              taskAffinity=com.cyanogenmod.filemanager
              realActivity=com.cyanogenmod.filemanager/.activities.NavigationActivity
              baseDir=/system/app/CMFileManager/CMFileManager.apk
              dataDir=/data/user/0/com.cyanogenmod.filemanager
              stateNotNeeded=false componentSpecified=true mActivityType=0
              compat={320dpi} labelRes=0x7f0c0008 icon=0x7f020062 theme=0x7f0e0000
              config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
              taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
              taskDescription: iconFilename=null label="null" color=ff1e88e5
              launchFailed=false launchCount=1 lastLaunchTime=-38s806ms
              haveState=false icicle=null
              state=RESUMED stopped=false delayedResume=false finishing=false
              keysPaused=false inHistory=true visible=true sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
              fullscreen=true noDisplay=false immersive=false launchMode=1
              frozenBeforeDestroy=false forceNewConfig=false
              mActivityType=APPLICATION_ACTIVITY_TYPE
              waitingVisible=false nowVisible=true lastVisibleTime=-37s955ms
              resizeMode=RESIZE_MODE_UNRESIZEABLE
        Task id #95//Stack  id为1中另外的Taask
        mFullscreen=true
        mBounds=null
        mMinWidth=-1
        mMinHeight=-1
        mLastNonFullscreenBounds=null
        * TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
          userId=0 effectiveUid=u0a13 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.android.launcher3
          affinity=org.codeaurora.gallery
          intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity}
          realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
          autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1
          rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
          Activities=[ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}]
          askedCompatMode=false inRecents=true isAvailable=true
          lastThumbnail=android.graphics.Bitmap@bbc499 lastThumbnailFile=/data/system_ce/0/recent_images/95_task_thumbnail.png
          stackId=1
          hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=true firstActiveTime=1601263244132 lastActiveTime=1601263244132 (inactive for 40s)
          * Hist #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}
              packageName=org.codeaurora.gallery processName=org.codeaurora.gallery
              launchedFromUid=10023 launchedFromPackage=com.android.launcher3 userId=0
              app=ProcessRecord{ff4ff7f 8258:org.codeaurora.gallery/u0a13}
              Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity bnds=[360,168][536,356] }
              frontOfTask=true task=TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
              taskAffinity=org.codeaurora.gallery
              realActivity=org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity
              baseDir=/system/priv-app/SnapdragonGallery/SnapdragonGallery.apk
              dataDir=/data/user/0/org.codeaurora.gallery
              stateNotNeeded=false componentSpecified=true mActivityType=0
              compat={320dpi} labelRes=0x7f0b00f1 icon=0x7f030001 theme=0x7f100035
              config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
              taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
              taskDescription: iconFilename=null label="null" color=fff5f5f5
              launchFailed=false launchCount=0 lastLaunchTime=-41s697ms
              haveState=true icicle=Bundle[mParcelledData.dataSize=1556]
              state=STOPPED stopped=true delayedResume=false finishing=false
              keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWN
              fullscreen=true noDisplay=false immersive=false launchMode=0
              frozenBeforeDestroy=false forceNewConfig=false
              mActivityType=APPLICATION_ACTIVITY_TYPE
              waitingVisible=false nowVisible=false lastVisibleTime=-41s87ms
              connections=[ConnectionRecord{d694795 u0 CR org.codeaurora.gallery/com.android.gallery3d.app.BatchService:@c63ab4c}]
              resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
    
        Running activities (most recent first):
          TaskRecord{56df812 #96 A=com.cyanogenmod.filemanager U=0 StackId=1 sz=1}
            Run #1: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
          TaskRecord{495a9e0 #95 A=org.codeaurora.gallery U=0 StackId=1 sz=1}
            Run #0: ActivityRecord{1c174fa u0 org.codeaurora.gallery/com.android.gallery3d.app.GalleryActivity t95}
    
        mResumedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
    
      Stack #0://Launcher所属的ActivityStack
      mFullscreen=true
      mBounds=null
        Task id #88
        mFullscreen=true
        mBounds=null
        mMinWidth=-1
        mMinHeight=-1
        mLastNonFullscreenBounds=null
        * TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
          userId=0 effectiveUid=u0a23 mCallingUid=1000 mUserSetupComplete=true mCallingPackage=android
          affinity=com.android.launcher3
          intent={act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher}
          realActivity=com.android.launcher3/.Launcher
          autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=1 mTaskToReturnTo=0
          rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
          Activities=[ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}]
          askedCompatMode=false inRecents=true isAvailable=true
          lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/88_task_thumbnail.png
          stackId=0
          hasBeenVisible=true mResizeMode=RESIZE_MODE_FORCE_RESIZEABLE isResizeable=false firstActiveTime=1601263245268 lastActiveTime=1601263245268 (inactive for 38s)
          * Hist #0: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
              packageName=com.android.launcher3 processName=com.android.launcher3
              launchedFromUid=0 launchedFromPackage=null userId=0
              app=ProcessRecord{7996cfe 5669:com.android.launcher3/u0a23}
              Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher }
              frontOfTask=true task=TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
              taskAffinity=com.android.launcher3
              realActivity=com.android.launcher3/.Launcher
              baseDir=/system/app/XXXLauncher3/XXXLauncher3.apk
              dataDir=/data/user/0/com.android.launcher3
              stateNotNeeded=true componentSpecified=false mActivityType=1
              compat={320dpi} labelRes=0x7f0a0001 icon=0x7f030001 theme=0x7f0d0002
              config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
              taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
              taskDescription: iconFilename=null label="null" color=ff222222
              launchFailed=false launchCount=0 lastLaunchTime=-1h27m5s112ms
              haveState=true icicle=Bundle[mParcelledData.dataSize=3940]
              state=STOPPED stopped=true delayedResume=false finishing=false
              keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
              fullscreen=true noDisplay=false immersive=false launchMode=2
              frozenBeforeDestroy=false forceNewConfig=false
              mActivityType=HOME_ACTIVITY_TYPE
              waitingVisible=false nowVisible=false lastVisibleTime=-39s442ms
              resizeMode=RESIZE_MODE_FORCE_RESIZEABLE
    
        Task id #94//Task对应的ID
        mFullscreen=true
        mBounds=null
        mMinWidth=-1
        mMinHeight=-1
        mLastNonFullscreenBounds=null
        * TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
          userId=0 effectiveUid=u0a14 mCallingUid=u0a14 mUserSetupComplete=true mCallingPackage=com.android.systemui
          affinity=com.android.systemui
          intent={flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840]}
          realActivity=com.android.systemui/.recents.RecentsActivity
          autoRemoveRecents=false isPersistable=false numFullscreen=1 taskType=2 mTaskToReturnTo=1
          rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE
          Activities=[ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}]
          askedCompatMode=false inRecents=true isAvailable=true
          lastThumbnail=null lastThumbnailFile=/data/system_ce/0/recent_images/94_task_thumbnail.png
          stackId=0
          hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE isResizeable=true firstActiveTime=1601263239735 lastActiveTime=1601263239735 (inactive for 44s)
          * Hist #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}
              packageName=com.android.systemui processName=com.android.systemui
              launchedFromUid=10014 launchedFromPackage=com.android.systemui userId=0
              app=ProcessRecord{3142ae0 4683:com.android.systemui/u0a14}
              Intent { flg=0x10804000 cmp=com.android.systemui/.recents.RecentsActivity bnds=[32,1024][688,1840] }
              frontOfTask=true task=TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
              taskAffinity=com.android.systemui
              realActivity=com.android.systemui/.recents.RecentsActivity
              baseDir=/system/priv-app/SystemUI/SystemUI.apk
              dataDir=/data/user_de/0/com.android.systemui
              stateNotNeeded=true componentSpecified=true mActivityType=2
              compat={320dpi} labelRes=0x7f0f0257 icon=0x7f020159 theme=0x7f1301e3
              config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w360dp h568dp 320dpi nrml port finger -keyb/v/h -nav/h s.5}
              taskConfigOverride={1.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}
              taskDescription: iconFilename=null label="null" color=ff212121
              launchFailed=false launchCount=0 lastLaunchTime=-1m32s445ms
              haveState=true icicle=Bundle[mParcelledData.dataSize=500]
              state=STOPPED stopped=true delayedResume=false finishing=false
              keysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
              fullscreen=true noDisplay=false immersive=false launchMode=3
              frozenBeforeDestroy=false forceNewConfig=false
              mActivityType=RECENTS_ACTIVITY_TYPE
              waitingVisible=false nowVisible=false lastVisibleTime=-46s419ms
              resizeMode=RESIZE_MODE_RESIZEABLE
    
        Running activities (most recent first):
          TaskRecord{a9ad0b9 #88 A=com.android.launcher3 U=0 StackId=0 sz=1}
            Run #1: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
          TaskRecord{ca4459f #94 A=com.android.systemui U=0 StackId=0 sz=1}
            Run #0: ActivityRecord{f344048 u0 com.android.systemui/.recents.RecentsActivity t94}
    
        mLastPausedActivity: ActivityRecord{9997f10 u0 com.android.launcher3/.Launcher t88}
    
      //当前持有焦点的Activity
      mFocusedActivity: ActivityRecord{dac4005 u0 com.cyanogenmod.filemanager/.activities.NavigationActivity t96}
      //持有焦点的ActivityStack
      mFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks} mLastFocusedStack=ActivityStack{d2f835e stackId=1, 2 tasks}
      mSleepTimeout=false
      mCurTaskIdForUser={0=96}
      mUserStackInFront={}
      mActivityContainers={0=ActivtyContainer{0}A, 1=ActivtyContainer{1}A}
      mLockTaskModeState=NONE mLockTaskPackages (userId:packages)=
        0:[]
     mLockTaskModeTasks[]
    
    
    


    二.为目标Activity查找/分配或者创建最优Task栈

      接着我们前面博客Android四大组件之Activity启动流程源码实现详解(一)未完成之使命,继续分析AS.startActivityLocked方法。在正式分析之前,我要在此提前打一个预防针,这是因为该方法涉及的知识点非常多,并且代码也很多,所以各位小伙们一定打起精神一鼓作气的将其拿下来(当然小伙们也可以抛开此章节,直接进入第三大章节分析后面的流程,因为这个并不影响Activity启动的整体流程分析)!
      startActivityLocked方法主要从代码逻辑上可以分为两大部分来阐述:

    • 第一大部分:
      1、初始化Activity启动状态
      2、计算launchFlag
      3、计算调用者的ActivityStack
      4、检查是否存在复用的TaskRecord
      5、对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)
      6、计算当前启动Activity所属的TaskRecord
      7、把当前启动的Activity放到所属TaskRecord的栈顶
    • 第二大部分:
      8、最后调用resumeFocusedStackTopActivityLocked创建正在启动的Activity、Paused当前resumed的Activity,
      9、以及resumed当前启动的Activity

    本大章节将重点分析第一大部分内容,不要问我有多少,我只能说很多很多!

    //[ActivityStarter.java]
    	/*	这里的sourceRecord是指发起调用者
    		r待启动的ActivityRecord,这是是在前面创建的一个ActivityRecord对象
    		startFlags表示启动目标Activity的flag,取值为0,
    		doResume表示是否要将Activity推入Resume状态,从上一个方法传入进来的参数值为true
    	*/
        private int startActivityUnchecked(final ActivityRecord r, 
        									ActivityRecord sourceRecord,
                							IVoiceInteractionSession voiceSession, 
                							IVoiceInteractor voiceInteractor,
                							int startFlags, boolean doResume, 
                							ActivityOptions options, 
                							TaskRecord inTask) {
    
    		//初始化Activity启动的一些状态,这里主要是根据启动模式的相关设置进行了一些变量的处理。比如newtask,document等等
            //初始化Activity启动状态,获取launchmode flag 同时解决一些falg和launchmode的冲突
    		setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                    voiceInteractor);//详见章节2.1
    
    		//计算目标Activity的launchMode模式
    		computeLaunchingTaskFlags();//详见章节2.2
    
    		//确定发起端的ActivityStack情况
            computeSourceStack();//详见章节1.3
    
            mIntent.setFlags(mLaunchFlags);//把前面解析得到的mLaunchFlags,设置目标Activity的launchMode启动模式
    
    		// 根据mLaunchFlags来查找是否有可重用的activity
    		/**
           * 这边主要是判断当前启动的Activity是否存在可以利用的Task
           * 当启动模式launchMode为singleTask、singleInstance,或者启动时
           * Flag设置为FLAG_ACTIVITY_NEW_TASK并没设置FLAG_ACTIVITY_MULTIPLE_TASK
           * 并且当前启动的Activity不是以startActivityForResult启动的,
           * 满足以上情况才会寻找是否存在有复用的Task。
           * 匹配规则:
           * 1、对于启动模式为singleInstance,遍历所有ActivityStack和Task的堆栈中查找
           *是否存在以当前启动Activity相同的Activity。
           * 2、其它情况下,遍历所有ActivityStack和Task的堆栈,查找Task中intent变量                                              
           *是否当前启动Activity相匹配,如果不存在,则去匹配task的亲和性(即
           *在AndroidManifest中android:taskAffinity定义的。
           */
    		mReusedActivity = getReusableIntentActivity();//详见2.4
    
            final int preferredLaunchStackId =
                    (mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;//此时mOptions为null
    
    		 //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    		 //做清理和拷贝工作...
            if (mReusedActivity != null) {//详见章节2.5
    			
    			...
    			//设置当前启动Activity的Task为复用的Task
                if (mStartActivity.task == null) {
                    mStartActivity.task = mReusedActivity.task;
                }
                if (mReusedActivity.task.intent == null) {
                    mReusedActivity.task.setIntent(mStartActivity);
                }
    
                /*
    			 *这边处理启动时设置FLAG_ACTIVITY_CLEAR_TOP时,要清除复用Task中存在与当前启动
    			 *Activity相同的Activity之上的Activity
    			 *举个例子:比如复用Task1中存在有Activity A,B,C,D,此时正在启动的Activity B,那么C**和D也要finish,另外此时如果B *为标准启动模式,并且没有设置FLAG_ACTIVITY_SINGLE_TOP,那么B也会finish。具体的读者可以跟进
    			 *mReusedActivity.task.performClearTaskForReuseLocked看下。
    			 */
                if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                        || mLaunchSingleInstance || mLaunchSingleTask) {
                    final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                            mStartActivity, mLaunchFlags);
                    if (top != null) {
                        if (top.frontOfTask) {
                            top.task.setIntent(mStartActivity);
                        }
                        ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
    					// 没必要新建实例,回调onNewIntent并将top移至前台
                        top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                                mStartActivity.launchedFromPackage);
                    }
                }
    
    			// 计算哪个task和activity要移至前台,必要时会进行task的清理工作
                mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
    
    			//如果被启动的对象和调用者是同一个,什么都不用做,只要正确恢复顶层的Activity
                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                    resumeTargetStackIfNeeded();
                    return START_RETURN_INTENT_TO_CALLER;
                }
    			//根据复用情况设置task
                setTaskFromIntentActivity(mReusedActivity);
    	
    			//mAddingToTask为true表示要新建,mReuseTask为空表示task被清除了
                if (!mAddingToTask && mReuseTask == null) {
                    resumeTargetStackIfNeeded();
                    return START_TASK_TO_FRONT;
                }
            }
    
            if (mStartActivity.packageName == null) {
                if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
                    mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                            -1, mStartActivity.resultTo, mStartActivity.resultWho,
                            mStartActivity.requestCode, RESULT_CANCELED, null);
                }
                ActivityOptions.abort(mOptions);
                return START_CLASS_NOT_FOUND;
            }
    
    
            final ActivityStack topStack = mSupervisor.mFocusedStack;
            final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
            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) {
                ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
                topStack.mLastPausedActivity = null;
                if (mDoResume) {
                    mSupervisor.resumeFocusedStackTopActivityLocked();
                }
                ActivityOptions.abort(mOptions);
                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                    return START_RETURN_INTENT_TO_CALLER;
                }
                top.deliverNewIntentLocked(
                        mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
                mSupervisor.handleNonResizableTaskIfNeeded(
                        top.task, preferredLaunchStackId, topStack.mStackId);
    
                return START_DELIVERED_TO_TOP;
            }
    
            boolean newTask = false;
            final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                    ? mSourceRecord.task : null;
    
            if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                    && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                newTask = true;
    			// 重用或者新建task
                setTaskFromReuseOrCreateNewTask(taskToAffiliate);
    
                if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
                    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
                }
                if (!mMovedOtherTask) {
                    updateTaskReturnToType(mStartActivity.task, mLaunchFlags, topStack);
                }
            } else if (mSourceRecord != null) {
                if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
                    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
                }
    
    			// 不是新建task的,重用原activity的task
                final int result = setTaskFromSourceRecord();
                if (result != START_SUCCESS) {
                    return result;
                }
            } else if (mInTask != null) {
                if (mSupervisor.isLockTaskModeViolation(mInTask)) {
                    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
                }
    
                final int result = setTaskFromInTask();
                if (result != START_SUCCESS) {
                    return result;
                }
            } else {
                setTaskToCurrentTopOrCreateNewTask();
            }
    
            mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
                    mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
    
            if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
                mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
            }
            if (newTask) {
                EventLog.writeEvent(
                        EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
            }
            ActivityStack.logStartActivity(
                    EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
            mTargetStack.mLastPausedActivity = null;
    		
    		/*把当前启动的Activity加入TaskRecord以及绑定WindowManagerService*/
    		mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    		...
            return START_SUCCESS;
        }
    

    该部分代码很长,很长!但是没有办法,阅读源码就是这么操蛋,我们只能一步步分解,强行分析了!在对该方法startActivityUnchecked刨丁解牛,我们先看看该方法牵涉到的返回值,以及意义!

    返回值定义 返回值含义
    START_CLASS_NOT_FOUND(-2) 无法找到目标Activity的类
    START_SUCCESS(0) 启动成功
    START_RETURN_INTENT_TO_CALLER(1) 当启动参数中带有START_FLAG_ONLY_IF_NEEDED标志时,如果目标Activity就是当前的调用者,则返回该值,启动结束
    START_TASK_TO_FRONT(2) 在已有任务中找到了目标Activity,则只需要把目标Activity挪到前台即可,启动结束
    START_DELIVERED_TO_TOP(3) 目标Activity位于任务栈顶,则只需要将Intent派送到栈顶的Activity即可,启动结束
    START_RETURN_LOCK_TASK_MODE_VIOLATION(5) 目标Activity的宿主任务处于LockTaskMode模式,且目标Activity的启动方式违背了LockTaskMode的规则,则不能启动目标Activity

    2.1 AS.setInitialState设置数据初始化状态

    //[ActivityStarter.java]
        private void setInitialState(ActivityRecord r,//表示要启动的目标Activity信息
        							ActivityOptions options, //options是附件信息,此时为null
        							TaskRecord inTask,
                					boolean doResume, //此处的doResume的值为true
                					int startFlags, //这里传入的startFlags为0
                					ActivityRecord sourceRecord,//发起端的Activity信息
                					IVoiceInteractionSession voiceSession, 
                					IVoiceInteractor voiceInteractor) {
            reset();//对所有变量进行重置
    
            mStartActivity = r;//将要启动的目标Activiyt信息赋值给mStartActivity 
            mIntent = r.intent;
            mOptions = options;
            mCallingUid = r.launchedFromUid;
            mSourceRecord = sourceRecord;
            mVoiceSession = voiceSession;
            mVoiceInteractor = voiceInteractor;
    
            mLaunchBounds = getOverrideBounds(r, options, inTask);
    		//获取Activity的启动模式,这些值是从<activity>标签中读取的,即目标Activity所定义的启动方式
    		 // 除了目标Activity定义的启动模式外,调用者也可以设置Activity的启动模式
        	// 这些参数都体现在Intent的Flags中
            mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
            mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
            mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
            
            /*
            	这里会根据启动模式来调整flag到NEW_DOCUMEN  如果intent中的和mainfest中的冲突,那么manfest的启动模式优先
    	        FLAG_ACTIVITY_NEW_DOCUMENT是打开一个文件的标识
    	        其处理流程遵循如下逻辑:
               	1、如果此Activity是由singleInstance或者singleTask的话且flag带了NEW_DOCUMENT,则需要去掉NEW_DOCUMENT和MULTIPLE_TASK的flag
               	2、如果不属于第一种情况则读取ActivityInfo中的documentLaunchMode和intent携带的flags对目标Activity的flag赋值
            */
            mLaunchFlags = adjustLaunchFlagsToDocumentMode(
                    r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
               
       		// 是否为后台启动任务的标志位
            mLaunchTaskBehind = r.mLaunchTaskBehind
                    && !mLaunchSingleTask && !mLaunchSingleInstance
                    && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
    
            /*如果是newTask的启动模式,那么会将resultTo设置为null。
    		*这里做了一个处理。这个活动被启动到一个新的任务中,而且还需要得到请求结果。
    		*那么,这是相当混乱的,因此,立即发送回一个取消,让新的任务继续启动像往常一样,不依赖于它的发起者
    		*也就是newTask的启动模式,是无法获取到请求结果的*/		
            sendNewTaskResultRequestIfNeeded();
    
    		 //如果设置了NEW_DOCUMENT标志同时此Activity不是其他Activity启动的
            //则在加上NEW_TASK的标志
            if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
            }
    
            if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                //对于后台启动的新任务,可以多任务运行
                if (mLaunchTaskBehind
                        || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
                    mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
                }
            }
    
            mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
    
    
            mDoResume = doResume;//此时的doReume为true所以不会走入此分支
            //当本次不需要resume时,则设置为延迟resume的状态
            if (!doResume || !mSupervisor.okToShowLocked(r)) {
                r.delayedResume = true;
                mDoResume = false;
            }
    
    		//此时mOptions为null不会走入此分支
            if (mOptions != null && mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
                r.mTaskOverlay = true;
                final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
                final ActivityRecord top = task != null ? task.getTopActivity() : null;
                if (top != null && !top.visible) {
    
                    mDoResume = false;
                    mAvoidMoveToFront = true;
                }
            }
    
    		/**FLAG_ACTIVITY_PREVIOUS_IS_TOP:
    		*如果给Intent对象设置了这个标记,这个Intent对象被用于从一个存在的Activity中启动一个新的Activity,
    		*那么新的这个	Activity不能用于接受发送给顶层activity的intent,这个新的activity的前一个activity被作为顶部activity
    		*如果设置FLAG_ACTIVITY_PREVIOUS_IS_TOP,当前Activity不会作为栈顶来启动新的Activity而是把当前Activity的前一个作为栈顶.简而言之,栈ABC启动D则栈变成ABD。所以sourceRecord设置为null
    		*/
            mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
    
            mInTask = inTask;
            if (inTask != null && !inTask.inRecents) {
                Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
                mInTask = null;
            }
    
            mStartFlags = startFlags;
    		//我们传入的startFlags为0不会走入此分支
            if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                ActivityRecord checkedCaller = sourceRecord;
                if (checkedCaller == null) {
                    checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
                            mNotTop);
                }
                if (!checkedCaller.realActivity.equals(r.realActivity)) {
                    //调用者 与将要启动的Activity不相同时,进入该分支
                    mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
                }
            }
    		//是否有动画
            mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
        }
    	//将启动将要涉及的相关变量都进行初始化
        private void reset() {
            mStartActivity = null;
            mIntent = null;
            mCallingUid = -1;
            mOptions = null;
    
            mLaunchSingleTop = false;
            mLaunchSingleInstance = false;
            mLaunchSingleTask = false;
            mLaunchTaskBehind = false;
            mLaunchFlags = 0;
    
            mLaunchBounds = null;
    
            mNotTop = null;
            mDoResume = false;
            mStartFlags = 0;
            mSourceRecord = null;
    
            mInTask = null;
            mAddingToTask = false;// 表示是否在传入的inTask中启动Actiivty,后面会根据实际情况重新设置该变量
            mReuseTask = null;
    
            mNewTaskInfo = null;
            mNewTaskIntent = null;
            mSourceStack = null;
    
            mTargetStack = null;
            mMovedOtherTask = false;
            mMovedToFront = false;
            mNoAnimation = false;
            mKeepCurTransition = false;
            mAvoidMoveToFront = false;
    
            mVoiceSession = null;
            mVoiceInteractor = null;
        }
    
    

      在正式开始掰持掰持上述源码前,我们先来捣鼓捣鼓几个概念,因为源码中会有涉及到,当然这部分知识我在博客中Android四大组件之Activity启动流程源码实现详解概要也有提到过:

    • 启动模式(launchMode):
    //[ActivityInfo.java]
    public class ActivityInfo extends ComponentInfo
            implements Parcelable {
        ...
        public static final int LAUNCH_MULTIPLE = 0;
        public static final int LAUNCH_SINGLE_TOP = 1;
        public static final int LAUNCH_SINGLE_TASK = 2;
        public static final int LAUNCH_SINGLE_INSTANCE = 3;
    	...
    }
    
    启动模式 对应特点
    LAUNCH_MULTIPLE(standard) 每次启动新Activity,都会创建新的Activity,这是最常见标准情形
    LAUNCH_SINGLE_TOP(singleTop) 当启动新Acitity,在栈顶存在相同Activity,则不会创建新Activity;其余情况同上
    LAUNCH_SINGLE_TASK(singleTask) 当启动新Acitity,在栈中存在相同Activity(可以是不在栈顶),则不会创建新Activity,而是移除该Activity之上的所有Activity;其余情况同上
    LAUNCH_SINGLE_INSTANCE(singleInstance) 每个Task栈只有一个Activity,其余情况同上
    • 启动Activity的flag常用值:
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    
    启动Activity常用Flag值 对应特点
    FLAG_ACTIVITY_NEW_TASK 将Activity放入一个新启动的Task
    FLAG_ACTIVITY_CLEAR_TASK 启动Activity时,将目标Activity关联的Task清除,再启动该Task,将该Activity放入该Task,也就是说,这个新启动的activity变为了这个空Tas的根activity.所有老的activity都结束掉。该flags跟FLAG_ACTIVITY_NEW_TASK配合使用
    FLAG_ACTIVITY_CLEAR_TOP 启动非栈顶Activity时,先清除该Activity之上的Activity。例如Task已有A、B、C三个Activity,启动A,则清除B,C。类似于SingleTop
    FLAG_ACTIVITY_PREVIOUS_IS_TOP 如果给Intent对象设置了这个标记,这个Intent对象被用于从一个存在的Activity中启动一个新的Activity,那么新的这个 Activity不能用于接受发送给顶层activity的intent,这个新的activity的前一个activity被作为顶部activity
    START_FLAG_ONLY_IF_NEEDED 该flag表示只有在需要的时候才启动目标Activity。也就是说如果调用者和被启动的是一个,那么就没有必要去进行重复的步骤了

    好了,让我们来开始分析源码setInitialState方法的业务逻辑,主要就是进行一些初始化,如下:

    • 首先调用通过reset方法,直接将所需要修改的变量进行了重置
    • 获取目标Activity在对应的AndroidManifest中配置的启动方式
    • 优化处理启动模式:
      1.如果是newTask,则将resultTo设置为空
      2.对FLAG_ACTIVITY_NEW_DOCUMENT的文档标识的处理
      3.对FLAG_ACTIVITY_PREVIOUS_IS_TOP启动标志的处理
      4.记录动画标识

    2.2 AS.computeLaunchingTaskFlags计算目标Activity的Task的flag

      是不是被1.1章节涉及到的概念整懵了,这还没有完呢,又要开始了!这就是我所说的为啥说本大章节是Activity中最难突破的点,那也啥办法呢只能一点点突破了!在正式开始该部分的源码分析前是时候放出看家法宝了(Android四大组件之Activity启动流程源码实现详解概要有简单掰扯过)!在这里插入图片描述

    //[ActivityStarter.java]
    	/**
    	  根据launchMode和Intent中的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式,
    	  结果保存在mLaunchFlags中。计算的过程不仅要考虑目标activity的launchMode,
    	  也要考虑原来activity的launchMode和Intent中所带着的flag
    	*/
        private void computeLaunchingTaskFlags() {
    		//当调用者不是来自Activity,但是又明确指定指定了目标task运行该Activity的话,这个情况比较少见
    		if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
    			//查找任务栈mInTask的intent信息,
                final Intent baseIntent = mInTask.getBaseIntent();
                /*
    	          TaskRecord由多个activityRecord组成,是我们平时所说的任务栈,
    	          里面包含着它所管理的activity列表(其中的关系详见上述图示)
    	          这里返回第一个没有结束的activity
    			*/
                final ActivityRecord root = mInTask.getRootActivity();
                if (baseIntent == null) {
                    ActivityOptions.abort(mOptions);
                    throw new IllegalArgumentException("Launching into task without base intent: "
                            + mInTask);
                }
    
    			
                if (mLaunchSingleInstance || mLaunchSingleTask) {
                	/*
                	  如果启动模式是LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK,
                	  那么必须保证堆栈是他们所运行的堆栈,否则就抛出异常
                	*/
                    if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
                        ActivityOptions.abort(mOptions);
                        throw new IllegalArgumentException("Trying to launch singleInstance/Task "
                                + mStartActivity + " into different task " + mInTask);
                    }
                    if (root != null) {
                        ActivityOptions.abort(mOptions);
                        throw new IllegalArgumentException("Caller with mInTask " + mInTask
                                + " has root " + root + " but target is singleInstance/Task");
                    }
                }
    
    			/*
    			  如果根部为空,说明里面还没有activity,可以把我们要启动的activity作为它的rootTask启动,
    			  所以会对这个task做初始化操作
    			*/
                if (root == null) {
                    final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
                            | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
                    mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
                            | (baseIntent.getFlags() & flagsOfInterest);
                    mIntent.setFlags(mLaunchFlags);
                    mInTask.setIntent(mStartActivity);
                    //mAddingToTask这个变量表示已经找到某个task来放置Activity,
                    //有可能是启动时指定的task还有可能是启动的sourceTask,反正就是不用再去遍历寻找task
                    mAddingToTask = true;//标记是否增加到栈中
                } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                	//当前栈根部不为空,但是启动模式是FLAG_ACTIVITY_NEW_TASK,那么不需要添加新的activity,
                	//只要直接把当前task带到前台显示即可,这个地方需要重点关注一下
                    mAddingToTask = false;
                } else {
                	//不是一个空的task,并且也没有设置FLAG_ACTIVITY_NEW_TASK启动参数,所以需要添加一个activity到这个task中,设置 mAddingToTask = true
                    mAddingToTask = true;
                }
    			
    			//说明用户指定的task是可用的,设置mReuseTask = mInTask
                mReuseTask = mInTask;
            } else {
                mInTask = null;
                /*
                  此时sourceRecord不为空或者用户没有指定mInTask。这种情况就需要设置mInTask为null,因为sourceRecord优先级大于mInTask. 这个条件还对特殊情况做了处理,保证要启动的activity尽量放到SourceRecord 之上
                */
                if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
                        && mSourceRecord.isFreeform())  {
                    mAddingToTask = true;
                }
            }
    
            if (mInTask == null) {
                if (mSourceRecord == null) {//未指定Task且没有sourceRecord,//根据调用方和要启动的activty的启动模式来进行调整。将acitivty启动模式调整为为newTask
                    //调用者并不是Activity context,则强制创建新task
                    if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {//如果其源任务栈也不存在,无法附加要启动的activity到sourceRecord的task中,则强制新建Task
                        Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
                                "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
                        mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                    }
                } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
                    //发起调用者的Activity带有single instance,这种activity只能自己独自在一个task上,
                	//所以新启动的activity也要添加FLAG_ACTIVITY_NEW_TASK参数,在新的task上启动activity
                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                } else if (mLaunchSingleInstance || mLaunchSingleTask) {
                    //目标Activity带有single instance或者single task,则创建新task
                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                }
            }
        }
    

      这细节分析起来的太操蛋了,太多细枝末节的东西了,看来Activity的TaskRecord的处理真的是一个难点啊!在computeLaunchingTaskFlags方法中根据发起端/目的端的launchMode和以及Intent中的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式,并且主要分了两个大类情况来处理:

    • 发起端的ActivityRecord信息记录为空,但是明确指定要启动的Activity所在的任务栈

      • 要使用的任务栈必须有baseIntent。也就是必须有任务栈创建时所使用的intent信息,否则抛异常
      • 如果启动模式是 singleInstance 或者 singleTask ,那么要使用的任务栈的根ActivityRecorkd必须为空。而且启动任务栈所使用的Component必须是当前Component。否则扔异常
      • 如果任务栈的根AcitivityRecord为空,那么指定的mInTask其实就是一个新的任务栈,修改启动模式mLaunchFlags 。并且标记mAddingToTask为true
      • 如果任务栈的根AcitivityRecord不为空,并且启动标识有newTask。那么标记mAddingToTask为false
      • 如果任务栈的根AcitivityRecord不为空,并且启动标识不为newTask。那么标记mAddingToTask为true
      • 将要启动的任务栈赋值给可复用的任务栈mReuseTask
    • 剩下的情况就是发起端的ActivityRecord信息记录不为空或者没有指定mInTask。这种情况直接将指定的mInTask清空

    上述操作猛如虎工资2500!当上述两种情况处理完成以后,上述方法会进行一次判断处理,如果指定运行的任务栈mInTask为空(包括没有设置,或者后来清空),那么会分情况对启动标识进行调整:

    • 如果调用方AcitivityRecord信息为空,这时候将要启动的目标acitivity既无法附加到调用方的任务栈中,也没有指定的执行的任务栈mInTask存在,那么此时Android系统只能直接强制将其增加newTaks启动标识,在新的任务栈中启动
    • 如果调用方的AcitivityRecord携带有启动标识位singleInstance,那么说明调用方需要独自在一个任务栈上,要启动的目标acitivity也无法附加到其任务栈,那么这时候直接将其增加newTaks启动标识,在新的任务栈中启动。
    • 如果要启动目标Activity的启动模式是singTask,或者singleInstance。那么增加newTaks启动标识

    分析至此我们可以得出一个结论就是computeLaunchingTaskFlags的主要功能就是根据发起端/目的端的launchMode和以及Intent中的携带的FLAG_ACTIVITY_NEW_TASK等flag综合计算activity的启动模式或者说调整启动目标Activiyt的启动模式。


    2.3 AS.computeSourceStack计算发起方Activity的栈

    //[ActivityStarter.java]
    	//确定发起端的Stack情况
        private void computeSourceStack() {
            if (mSourceRecord == null) {
                mSourceStack = null;
                return;
            }
            if (!mSourceRecord.finishing) {
    			//当调用者Activity不为空,且不处于finishing状态,则其所在栈赋于sourceStack
                mSourceStack = mSourceRecord.task.stack;
                return;
            }
             //如果调用方已经finish了,那么就无法将其作为我们的源任务栈了,这时候,要强行添加FLAG_ACTIVITY_NEW_TASK标志使activity启动到一个新的task中
            if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
                Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
                        + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
                //保存task的intent信息和taskinfo信息是为了新建task的时候尝试恢复这个task
                mNewTaskInfo = mSourceRecord.info;
                mNewTaskIntent = mSourceRecord.task.intent;
            }
            mSourceRecord = null;
            mSourceStack = null;
        }
    

      好家伙嘛!终于来了一个简单点的逻辑了,分为三部分处理:

    • 如果发起方的Activity的mSourceRecord为null,那么发起方Activity的栈就置为null吗,没有儿子那来的父母不是
    • 如果发起方的mSourceRecord不为null,且没有被结束的话,直接是从发起方的ActivityRecord拿到ActivityStack对象
    • 而如果发起方已经结束了,则添加newTask标识来启动新的任务

    2.4 AS.getReusableIntentActivity查找可复用的Activity

    //[ActivityStarter.java]
        private ActivityRecord getReusableIntentActivity() {
        	/*
    	    	标识是否可以放入一个已经存在的栈
    	        该条件成立的前提是:
    	        1.判断方法是设置了FLAG_ACTIVITY_NEW_TASK,但是并非MULTIPLE_TASK
    	        2.或者LAUNCH_SINGLE_INSTANCE或者LAUNCH_SINGLE_TASK模式
        	*/
            boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
                    (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
                    || mLaunchSingleInstance || mLaunchSingleTask;
    		//还要根据目标Activiyt任务栈是否为空来进行判断
            putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
            ActivityRecord intentActivity = null;
            if (mOptions != null && mOptions.getLaunchTaskId() != -1) {//跳过此处
    			...
            } else if (putIntoExistingTask) {//可以放入一个已经存在的Task栈
                if (mLaunchSingleInstance) {//启动模式是LAUNCH_SINGLE_INSTANCE,那么因为其是一种全局唯一的,需要进行搜索遍历
                   /*
                    findActivityLocked方法根据传入的Intent和ActivityInfo这两个参数可以获取一个Activity的包名,
                    该方法会从栈顶至栈底遍历ActivityStack中的所有Activity,如果包名匹配成功,就返回
                   */
                   intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info, false);
                } else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
                    intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
                            !mLaunchSingleTask);
                } else {
                	//这里是最常见的形式,mStartActivity是需要启动的Activity,intentActivity是找到的可用的Task中顶部的Activity		
                	/*
                		该方法的功能是找到目标ActivityRecord(target)所在的任务栈(TaskRecord),如果找到,则返回栈顶的ActivityRecord,否则,返回null
                	*/
                    intentActivity = mSupervisor.findTaskLocked(mStartActivity);
                }
            }
            return intentActivity;
        }
    

      getReusableIntentActivity方法主要是来查找是否有可以重用的activity,这个只对启动模式为LAUNCH_SINGLE_INSTANCE和LAUNCH_SINGLE_TASK或者FLAG_ACTIVITY_NEW_ TASK不为0的Activity才有用,对于standard的activity,该方法永远返回null。
    如果putIntoExistingTask为true表示可以进行复用,那么接着就根据情况进行不同的遍历查找:

    • 启动模式是singleInstance。这种启动模式属于全局唯一的。通过ASS的findActivity 方法来查找是否存在可以复用的Activity
    • 如果启动表示有 FLAG_ACTIVITY_LAUNCH_ADJACENT ,也是通过通过ASS的findActivity的来查找是否存在可以复用的Activity
    • 其他情况则调用ASS的findTaskLocked方法来查找搜索是存在目标Activity所在的任务栈,如果找到则返回栈顶的ActiviytRecord

    对于以上的查找就不分析了,这个牵涉的东西太多了,后面打算开辟专门章节来分析。


    2.5 存在复用ActivityRecord处理

    假如此时我们找到了复用的ActivityRecord,我们看看Android是怎么对其进行相关处理的。

    //[ActivityStarter.java]
        private void startActivityUnchecked(ActivityRecord r,//表示要启动的目标Activity信息
        							ActivityOptions options, //options是附件信息,此时为null
        							TaskRecord inTask,
                					boolean doResume, //此处的doResume的值为true
                					int startFlags, //这里传入的startFlags为0
                					ActivityRecord sourceRecord,//发起端的Activity信息
                					IVoiceInteractionSession voiceSession, 
                					IVoiceInteractor voiceInteractor) {
    		...
    
    		 //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    		 //做清理和拷贝工作...
    		 /*
    	       此时当前的Task列表中存在有复用的Activity
    	       可能为相同的Activity或者具有相同的affinity的task
    	       如果是第一次启动某个应用或者从adb am中启动以及第一次启动Launcher
    	       那么复用的TaskRecord为null
    		 */
            if (mReusedActivity != null) {
    			...			
    			//设置当前启动Activity的Task为复用的Task
                if (mStartActivity.task == null) {
                    mStartActivity.task = mReusedActivity.task;
                }
                //设置可以复用Activity所属的TaskRecord的初始intent为目标Activity的ActivityRecord
                if (mReusedActivity.task.intent == null) {
                    mReusedActivity.task.setIntent(mStartActivity);
                }
    
    
    			//清除task中复用的activity上面的activity
                if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                        || mLaunchSingleInstance || mLaunchSingleTask) {
    	               /*
    				 	这边处理启动时设置FLAG_ACTIVITY_CLEAR_TOP时,要清除复用activity所属TaskRecord之上的activity
    				 	举个例子:比如复用Task1中存在有Activity A,B,C,D,此时正在启动的Activity B,那么C和D也要finish
    				 	如果找到的可复用的activity的launchMode为LAUNCH_MULTIPLE,并且目标Activity没有设置为FLAG_ACTIVITY_SINGLE_TOP那么此时也会将可复用activity清除
    				 	对于要启动的activity的启动模式为LAUNCH_MULTIPLE的,performClearTaskForReuseLocked返回值top肯定是空的
    				 */
                    final ActivityRecord top = mReusedActivity.task.performClearTaskForReuseLocked(
                            mStartActivity, mLaunchFlags);   //[详见章节2.6]
                    if (top != null) {
                        if (top.frontOfTask) {//如果该ActivityRecord是所属任务栈的root activity,那么将目标activity设置为栈顶的Activity      		
                            top.task.setIntent(mStartActivity);
                        }
                        ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
    					// 没必要新建实例,回调onNewIntent并将top移至前台
                        top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                                mStartActivity.launchedFromPackage);
                    }
                }
    
    			// 将复用ActivityRecord所属TaskRecord移动到顶端,必要时会进行task的清理工作
                mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);  //详见章节[2.7]
    
    			//对于复用Task情况下START_FLAG_ONLY_IF_NEEDED这个FLAG只是resumed
               //该flag表示只有在需要的时候才启动目标Activity。也就是说如果调用者和被启动的是一个,那么就没有必要去进行重复的步骤了
                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                	//resume显示到前台
                    resumeTargetStackIfNeeded();
                    return START_RETURN_INTENT_TO_CALLER;
                }
                //根据intent情况设置TaskRecord
                setTaskFromIntentActivity(mReusedActivity);//[详见章节2.8]
    
    			//如果不需要把当前启动的Activity增加到Task并且不存在复用Task
                //那么仅仅进行resumed过程
                //mAddingToTask为true表示要新建,mReuseTask为空表示task被清除了
                if (!mAddingToTask && mReuseTask == null) {
    				//调用显示到前台
                    resumeTargetStackIfNeeded();
                    return START_TASK_TO_FRONT;
                }
            }				
    	...
    }
    

      在找到可以复用的ActivityRecord以后,startActivityUnchecked方法的处理逻辑远远还没有结束,依旧会继续着相关逻辑的处理:

    • 如果目标Activity的所属TaskRecord为null,则将查找到的可复用的Activity的所属TaskRecord填充
    • 如果可复用Activity所属TaskRecord的初始Activity为null,则使用目标Activity填充
    • 当我们启动目标Activity时候如果设置了FLAG_ACTIVITY_CLEAR_TOP标志位,或者目标Activiyt在AndroidManifest中设置了singleTask/singleInstance等启动模式说明此时需要清掉TaskRecord的数据。这时候会调用 performClearTaskForReuseLocked 方法将目标Activity上面的所有的Activity,并将当前activity置顶并返回顶部的ActivityRecord信息。最后调用 deliverNewIntent 方法
    • 最后不管是否进行了栈顶数据的清除。接下来就要将我们可以复用的Activity所在的TaskRecord移动到其所在的ActivityStack的顶部

    2.6 TaskRecord.performClearTaskForReuseLocked

      本来想给上述标题添加一个中文注解,但是吗有时候真的是只可意会不可言传啊,上面的英文原文反而更觉贴切!

    //[TaskRecord.java]
    
        ActivityRecord performClearTaskForReuseLocked(
        				ActivityRecord newR,//目标Activity 
        				int launchFlags//启动目标Activity的flag
        				) {
            mReuseTask = true;
            final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
            mReuseTask = false;
            return result;
        }
    
    	final ArrayList<ActivityRecord> mActivities;//存储TaskRecord管理的ActivityRecord
    	
        final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
            int numActivities = mActivities.size();
            //注意,此处是从TaskRecord的栈定开始遍历
            for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
                ActivityRecord r = mActivities.get(activityNdx);
                if (r.finishing) {
                    continue;
                }
                //找到了合适的activity,那么所有位于它上面的目标都需要结束
                //注意此处的equal有被重写,主要通过判断报名和类名是否一直
                if (r.realActivity.equals(newR.realActivity)) {
                    final ActivityRecord ret = r;
    
                    for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
                        r = mActivities.get(activityNdx);
                        if (r.finishing) {
                            continue;
                        }
                        ActivityOptions opts = r.takeOptionsLocked();
                        if (opts != null) {
                            ret.updateOptionsLocked(opts);
                        }
                        if (stack != null && stack.finishActivityLocked(
                                r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                            --activityNdx;
                            --numActivities;
                        }
                    }
    
      				//如果要复用的activity是multi模式,并且目标Activity没有设置FLAG_ACTIVITY_SINGLE_TOP启动模式那么也会调用finish结束掉
                    if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
                            && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
                        if (!ret.finishing) {
                            if (stack != null) {
                                stack.finishActivityLocked(
                                        ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
                            }
                            return null;
                        }
                    }
    
                    return ret;
                }
            }
    
            return null;
        }
    

      performClearTaskForReuseLocked方法不是特别复杂,主要是遍历TaskRecord对象实例中的ActivityRecord列表mActivities,然后依据一定的规则清除可复用TaskRecord栈中的ActivityRecord,其遍历清除遵循的逻辑如下:

    • 以倒序方式遍历mActivities(即从尾部开始遍历,这个也符合栈的存储结构),查找到被复用的Activity
    • 找到被复用的Activity以后,往尾部一次循环,调用ActivityStack的 finishActivityLocked 方法来结束掉对应的Activity,并减少引用数
    • 经过上述遍历清楚规则以后,最后还有一个规则就是如果要复用的activity是multi模式,并且目标Activity没有设置FLAG_ACTIVITY_SINGLE_TOP启动模式那么也会调用finish结束掉,也会结束掉当前这个复用的Activity。并且返回null,如果这个返回了null的话,就不会调用复用的activity的 deliverNewIntent 方法,相当于会重新启动。

    经过上面的步骤以后,不管是否进行了栈顶数据的清除,接下来就要将我们可以复用的Activity所在的TaskRecord移动到其所在的ActivityStack的顶部。


    2.7 TaskRecord.setTargetStackAndMoveToFrontIfNeeded

      说实话这个博客中的各种Stack和Task的分析,我自己都要吐了,太残暴了这些个东西。尼玛,有啥办法只能硬啃了。我们接着分析setTargetStackAndMoveToFrontIfNeeded看看它是怎么处理我们将要启动Activity的Stack以及Task的,又是各种的一顿操作啊!

    //[TaskRecord.java]
    	//这里的入参参数为可复用ActivityRecord 
        private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
        	//获取可复用ActivityRecord所属ActivityStack
            mTargetStack = intentActivity.task.stack;
            mTargetStack.mLastPausedActivity = null;
    		
    		//获取当前前台的ActivityStack,ASS中保存着所有的ActivityStack 
            final ActivityStack focusStack = mSupervisor.getFocusedStack();
    		//获取当前前台ActivityStack栈顶的ActivityRecord
            ActivityRecord curTop = (focusStack == null)
                    ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
    
    		//判断顶部的栈是否符合要求(即判断现在栈顶的栈是否为能够复用的activityrecord所在的栈)
            if (curTop != null
                    && (curTop.task != intentActivity.task || curTop.task != focusStack.topTask())
                    && !mAvoidMoveToFront) {
                    
                //增加一个标记,标识这个task是从任务栈的后面移动上来的    
                mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                
    			//这里的mSourceRecord表示的是发起端,此处是判断合法性
                if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
                        mSourceStack.topActivity().task == mSourceRecord.task)) {
                    if (mLaunchTaskBehind && mSourceRecord != null) {
                        intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
                    }
                    mMovedOtherTask = true;
    
    				 //willclearTask表明是否同时使用了NEW_TASK 和 CLEAR_TASK的flag
                    final boolean willClearTask =
                            (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
                    if (!willClearTask) {//不需要清空,那么就需要将复用的task移至栈顶
    	
    					//根据规则获取当前要启动activity所属的ActivityStack栈
                        final ActivityStack launchStack = getLaunchStack(
                                mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
    
    					//当要启动的栈与目标一致或者要启动的栈为空。这是我们一般的标准流程。会调用moveTaskToFrontLocked方法,将当前栈移动到与用户交互的栈顶
                        if (launchStack == null || launchStack == mTargetStack) {
                            mTargetStack.moveTaskToFrontLocked(
                                    intentActivity.task, mNoAnimation, mOptions,
                                    mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
                            mMovedToFront = true;
                         //其它情况
                        } else if (launchStack.mStackId == DOCKED_STACK_ID
                                || launchStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
                            if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
    							//这边是把复用的Task移动到其它的ActivityStack
                                mSupervisor.moveTaskToStackLocked(intentActivity.task.taskId,
                                        launchStack.mStackId, ON_TOP, FORCE_FOCUS, "launchToSide",
                                        ANIMATE);
                            } else {							
                                mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
                                        mOptions, mStartActivity.appTimeTracker,
                                        "bringToFrontInsteadOfAdjacentLaunch");
                            }
                            mMovedToFront = true;
                        }
                        mOptions = null;
                    }
                    updateTaskReturnToType(intentActivity.task, mLaunchFlags, focusStack);
                }
            }
            //这边表示如果不需要Task移动,移动targetStack到前台
            if (!mMovedToFront && mDoResume) {
                mTargetStack.moveToFront("intentActivityFound");
            }
    
            mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.task, INVALID_STACK_ID,
                    mTargetStack.mStackId);
    
            if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
            }
            return intentActivity;
        }
    

      感觉分析这块的代码,每次都是对我脑细胞和精神的一次摧残啊!我们来看看这个方法的大致流程:

    • 从ASS中找到当前和用户交互ActivityStack,然后从ActivityStack中找到正在和用户交互的ActivityRecord。同时找到其所在的任务栈(TaskRecord)(此处这几者之间牵涉的关系详见章节一)

    • 当发现当前栈顶的TaskRecord和我们要启动的Activity所使用的TaskRecord不是同一个时,这时候如果设置的标志位不会清空栈顶的信息的话,需要将要目标TaskRecord移动到栈顶位置。但是这个移动也需要分情况来进行

      1.首先通过getLaunchStack方法获取目标ActivityStcak信息intentTask。
      2.这时候会比较我们要启动的ActivityStack和当前复用的ActivityRecord所对应的ActivityStack作比较,然后根据不同情况走不同的分支

      • 当要启动的栈(launchStack)与目标(mTargetStack)一致,或者要启动的栈为空。则调用 moveTaskToFrontLocked 将对应的TaskRecord移动到栈顶位置
      • 当要启动的栈(launchStack)为分屏模式且flag满足FLAG_ACTIVITY_LAUNCH_ADJACENT则调用ASS的moveTaskToStackLocked迁移到lauchStack 中
      • 要启动的栈是其它模式则调用moveTaskToFrontLocked 将对应的TaskRecord移动到栈顶位置

    2.7.1 ActivityStack.moveTaskToFrontLocked将TaskRecord移动到栈顶

    //[ActivityStack.java]
    	//此处的入参TaskRecord为可以复用的TaskRecord
        final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
                AppTimeTracker timeTracker, String reason) {
            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
    
            final int numTasks = mTaskHistory.size();//获取AS中有多少TaskRecord
            final int index = mTaskHistory.indexOf(tr);//获取入参的tr在当前的AS中的位置
            if (numTasks == 0 || index < 0)  {//异常情况处理
                if (noAnimation) {
                    ActivityOptions.abort(options);
                } else {
                    updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
                }
                return;
            }
    
            if (timeTracker != null) {
                for (int i = tr.mActivities.size() - 1; i >= 0; i--) {
                    tr.mActivities.get(i).appTimeTracker = timeTracker;
                }
            }
    
    		
            //将Task移动到ActivityStack的栈顶端
            insertTaskAtTop(tr, null);
    
            //获取到TaskRecord的栈顶activity
            ActivityRecord top = tr.getTopActivity();
            if (!okToShowLocked(top)) {//判断是否可见
                addRecentActivityLocked(top);
                ActivityOptions.abort(options);
                return;
            }
            
            //获取到ActivityStack中顶部正在运行的Activity
            //这时候stack的topActivity应该是上一步已经移到栈复用的Task
            ActivityRecord r = topRunningActivityLocked();
            
     		/*
    	 		更新AMS中的focusedActivity
    	        这边会把当前Activity所属的Stack移到栈顶,
    	   		并且会更新ActivityStackSupervisor中的
    	        mLastFocusedStack、mFocusedStack这两个变量
          	*/
            mService.setFocusedActivityLocked(r, reason);
    
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
            if (noAnimation) {
                mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
                if (r != null) {
                    mNoAnimActivities.add(r);
                }
                ActivityOptions.abort(options);
            } else {
                updateTransitLocked(TRANSIT_TASK_TO_FRONT, options);
            }
            
    		//调用持有焦点的任务栈的顶部Activity的onResume()方法
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
            EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
    
            if (VALIDATE_TOKENS) {
                validateAppTokensLocked();
            }
        }
    

      前面我们简单的总结了moveTaskToFrontLocked的功能就是将TaskRecord移动到ActivityStack,其执行该流程的主要步骤如下:

    • 将可复用TaskRecord插入到ActivityStack的栈顶端,至于是那个ActivityStack这个要根据实际情况来定
    • 获取ActivityStack中顶部正在运行的Activity,这时候stack的topActivity应该是上一步已经移到栈复用的Task
    • 更新AMS中的focusedActivity,这边会把当前Activity所属的Stack移到栈顶
    • 调用持有焦点的任务栈的顶部Activity的onResume()方法

    让我们回过头来继续重看一下setTargetStackAndMoveToFrontIfNeeded方法,可以看到经过我们的分析可知此时当前启动Activity可以复用的Task已经移动到了栈顶了。

    到现在为止,我们已经可以复用的ActivityRecord的TaskRecord移动到交互栈顶。这时候还没有over战斗依然在进行,我们回到章节2.5看到此时会根据实际的情况对可复用的Activity信息,进行一些整理工作。


    2.8 AS.setTaskFromIntentActivity对复用Task根据intent情况继续处理

    //[ActivityStarter.java]
    	//注意此时传入的参数为可复用ActivityRecord
        private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
    		//设置了FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK标志位的复用的Task会finish所有的Activity,并且重新
    //更新复用Task信息的当前启动的Activit
            if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
                mReuseTask = intentActivity.task;
                mReuseTask.performClearTaskLocked();
                mReuseTask.setIntent(mStartActivity);
                mMovedOtherTask = true;
            } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
                    || mLaunchSingleInstance || mLaunchSingleTask) {
                //清空栈,这里跟之前的2.6章节栈顶数据的清除操作相似,但是那里处理的是top不为空,这里处理的是top为空的情况,也就是launchMode == ActivityInfo.LAUNCH_MULTIPLE
                ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
                        mLaunchFlags);
                if (top == null) {
                    mAddingToTask = true;
                    mSourceRecord = intentActivity;
                    final TaskRecord task = mSourceRecord.task;
                    if (task != null && task.stack == null) {
                        mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
                                null /* bounds */, mLaunchFlags, mOptions);
                        mTargetStack.addTask(task,
                                !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
                    }
                }
            }
            任务栈顶部的activity和要启动的activity是同一个 
            else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
            	//如果是sigleTop,那么就调用deliverNewIntent
                if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
                        && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity,
                            intentActivity.task);
                    if (intentActivity.frontOfTask) {//如果是栈的根activity,那么设置
                        intentActivity.task.setIntent(mStartActivity);
                    }
                    intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                            mStartActivity.launchedFromPackage);
                } else if (!intentActivity.task.isSameIntentFilter(mStartActivity)) {
                 	//如果不是singleTop,那么认为是需要启动一个新的activity
                    mAddingToTask = true;
                    mSourceRecord = intentActivity;
                }
            } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
             // 对FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标志出处理,这个主要用于快捷图标和或者从通知启动,这种情况需要替换task最上面的activity,所以需要添加activity到task中
                mAddingToTask = true;
                mSourceRecord = intentActivity;
            } else if (!intentActivity.task.rootWasReset) {
                intentActivity.task.setIntent(mStartActivity);
            }
        }
    

      再接再厉继续分析,让我们看看此方法中会对可复用的Activity所在的ActivityStack和TaskRecord做怎么样的处理:

    • 如果设置了FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK标志位,那么mReuseTask设置为可以复用的intentActivity的任务栈
    • 如果设置了清空了FLAG_ACTIVITY_CLEAR_TOP栈或者使用了singleInstance或者singleTask的一种,此时会拿到顶部的Task,然后重新添加到ActivityStack中
    • 如果要启动的Activity和当前顶部的Activity是同一个,会根据情况调用onNewIntent方法

    此时对于可复用的的Activity所在的TaskRecord处理已经完全完结了,此时已经将TaskRecord移动到栈顶位置了,这其中的各种切换逻辑真的是眼花缭乱啊,让人搞得晕头转向!


    2.9 存在复用ActivityRecord处理小结

      存在复用ActivityRecord处理的处理已经分析完毕了,各位小伙们真的理解了吗!我想没有,因为我也么有绕出来,其中涉及的各种场景太多了,看来还是得带入实际情况进行分析,但是这个就脱离我们本篇的范畴了,因为我们本篇重点讲解Activity的启动主流程!我们这里还是简单的对存在复用ActivityRecord处理小结一下,经过上述繁琐的处理对于可复用的的Activity所在的TaskRecord已经移动到栈顶位置了,其基本的调用流程如下:

    AS.startActivityUnchecked(...)
    	mReusedActivity.task.performClearTaskForReuseLocked(...)//清除task中复用的activity上面的activity
    	AS.setTargetStackAndMoveToFrontIfNeeded(...)// 将复用ActivityRecord所属TaskRecordy和ActivityStack移动到顶端,必要时会进行task的清理工作
    	AS.setTaskFromIntentActivity(...)//根据intent的情况对复用的Task进行调整
    

    如果读者朋友们,只想从整理上了解Activity的启动流程,那么第二大章节阅读过程中如果有问题也没有用关系,因为这个并不牵涉到整体流程的分析。


    2.10 继续AS.startActivityUnchecked未完成之使命处理目标Activity不存在的情况

      当存在复用ActivityRecord时,经过前面章节一系列的处理此时已将将可复用activty替换成现在的目标activty,也就不用新建task了。那么生活还得继续,让我们跳出reusedActivity不为空的情况,接着继续后续的分析。

    //[ActivityStarter.java]
    	/*	这里的sourceRecord是指发起调用者
    		r是指本次的将要启动的Activity
    		startFlags为启动目标Activity设置的flag值
    		doResume的值为true
    	*/
        private int startActivityUnchecked(final ActivityRecord r, 
        									ActivityRecord sourceRecord,
                							IVoiceInteractionSession voiceSession, 
                							IVoiceInteractor voiceInteractor,
                							int startFlags, boolean doResume, 
                							ActivityOptions options, 
                							TaskRecord inTask) {
    
    		...
    
    		 //如果找到了可重用的activity,需要清理掉原来的信息,并把当前启动的activity的信息拷贝进去
    		 //做清理和拷贝工作...
            if (mReusedActivity != null) {
    			...
            }
    
            if (mStartActivity.packageName == null) {//异常处理
                if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
                    mStartActivity.resultTo.task.stack.sendActivityResultLocked(
                            -1, mStartActivity.resultTo, mStartActivity.resultWho,
                            mStartActivity.requestCode, RESULT_CANCELED, null);
                }
                ActivityOptions.abort(mOptions);
                return START_CLASS_NOT_FOUND;
            }
    
    		//获取当前前台的ActivityStack 以及ActivityRecord 
            final ActivityStack topStack = mSupervisor.mFocusedStack;
            final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
    		//是否需要启动新的Activity标记,一长串的判断
            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) {//不需要重新启动,那么使用复用逻辑,将当前activity显示到前端即可
                ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
                topStack.mLastPausedActivity = null;
                if (mDoResume) {//此时为true
                    mSupervisor.resumeFocusedStackTopActivityLocked();
                }
                ActivityOptions.abort(mOptions);
                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                    return START_RETURN_INTENT_TO_CALLER;
                }
    			//调用NewIntent方法
                top.deliverNewIntentLocked(
                        mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
                mSupervisor.handleNonResizableTaskIfNeeded(
                        top.task, preferredLaunchStackId, topStack.mStackId);
    
                return START_DELIVERED_TO_TOP;
            }
        }
    

      通过代码分析我们可知此时判断当前顶部运行的Activity是否是我们所要启动的Activity,并且启动模式是singTop或者singleTask,如果是的话,则不会新建Activity,而是调用onResume和newIntent方法。因为这两种模式下,如果顶层是当前Activity的话,都不会启动新的Activity。这也就是我们常说的 A->B->C ,此时如果C的模式是singleTop,这时候再启动C的话,栈内仍然是A->B->C。这里很明显不是此种情况!

    革命仍未成功还需继续努力,让我们接着对startActivityUnchecked后续源码继续分析

    //[ActivityStarter.java]
    		//表示是否需要创建新的任务栈
            boolean newTask = false;
            final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
                    ? mSourceRecord.task : null;
    
            /*
            	如果要启动的目标Activity没有对应的resultTo,
            	并且也没有添加到对应栈中
            	而且设置了FLAG_ACTIVITY_NEW_TASK。
            	mAddingToTask为false说明没有找到对应的栈来启动我们的Activity。
                所以会通过创建或者复用一个栈来存放Activity
            */
            if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                    && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
                // 该类情况表示要在一个新的任务中启动Activity
                newTask = true;
    			// 重用或者新建task
                setTaskFromReuseOrCreateNewTask(taskToAffiliate);//详见章节2.10.1
    			...
            }
    		/*
    			当mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上。
             	一般情况下,mSourceRecord就是调用者,譬如通常的Launcher启动或者发起端的启动
            	但也有特殊情况,举个例子,如果启动模式为singleTask,栈中又不存在相同的Activity时,
            	mSourceRecord就是栈顶的Activity
    		*/
    		else if (mSourceRecord != null) {        
    			...
    			// 不是新建task的,重用原activity的task
    			// 该类情况下,宿主栈就是调用者Activity所在的ActivityStack。
            	// 处理方式也大同小异,把宿主任务挪到栈顶,针对launchFlags做一些调整
                final int result = setTaskFromSourceRecord();//详见章节2.10.2
                if (result != START_SUCCESS) {
                    return result;
                }
            } else if (mInTask != null) {//启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask,在指定的任务栈中启动Activity
    
                if (mSupervisor.isLockTaskModeViolation(mInTask)) {
                    Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                    return START_RETURN_LOCK_TASK_MODE_VIOLATION;
                }
    
                final int result = setTaskFromInTask();//详见2.10.3
                if (result != START_SUCCESS) {
                    return result;
                }
            } else {
    			//该类情况表示既不是从一个Activity启动,也不是在新的任务中启动,都不是则直接找焦点的ActivityStack上栈顶的Task,直接绑定,这种情况比较少见
    			
    			setTaskToCurrentTopOrCreateNewTask();//详见章节2.10.4
            }
    

      说实话这种逻辑性的代码分析起来很操蛋,也很容易让人陷入其中不能自拔,但是生活还得继续着,代码也得分析!上述的源码主要根据实际情况来继续进行要启动的Activity栈信息的处理,这里的处理逻辑又分为如下几种情况:

    • 如果要启动的目标Activity没有对应的resultTo,并且也没有指定mInTask,并且也没有添加到对应栈中,而且更是设置了FLAG_ACTIVITY_NEW_TASK,此时说明没有找到对应的栈来启动我们的Activity,则会调用setTaskFromReuseOrCreateNewTask继续处理
    • 如果发起端的mSourceRecord不为空,把新的ActivityRecord绑定到启动者的TaskRecord上
    • 如果启动时指定了目标栈(mInTask),ActivityRecord绑定到mInTask。
    • 如果都不是则直接找焦点的ActivityStack上栈顶的Task,直接绑定

    依然还没有完,Activity启动中的生命周期一个也没有看到!尼玛,还是对上述每种情况下是如何寻找任务栈的方式来简单来进行一下分析!

    2.10.1 AS.setTaskFromReuseOrCreateNewTask

    //[ActivityStarter.java]
        private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
    		//获取当前持有焦点的ActivityStack
            mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
                    mOptions);
    		//如果复用的任务栈(TaskRecord)为空,说明没有可以让我们用来使用的任务栈
            if (mReuseTask == null) {
            	//创建任务栈
                final TaskRecord task = mTargetStack.createTaskRecord(
                        mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                        mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                        mNewTaskIntent != null ? mNewTaskIntent : mIntent,
                        mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
                 //设置目标Activity的任务栈为新建的task
                mStartActivity.setTask(task, taskToAffiliate);
                if (mLaunchBounds != null) {
                    final int stackId = mTargetStack.mStackId;
                    if (StackId.resizeStackWithLaunchBounds(stackId)) {
                        mService.resizeStack(
                                stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
                    } else {
                        mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
                    }
                }
                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                        "Starting new activity " +
                                mStartActivity + " in new task " + mStartActivity.task);
            } else {
            	//设置目标Activity的任务栈为新建的task
                mStartActivity.setTask(mReuseTask, taskToAffiliate);
            }
        }
    

    setTaskFromReuseOrCreateNewTask方法的处理逻辑比较简单,总结归纳起来如下:

    • 获取系统当前的持有焦点的ActivitytStack对象mTargetStack
    • 接着判断是否存在可以复用的TaskRecord,如果没有可复用TaskRecord则通过mTargetStack的方法createTaskRecord创建,然后将目标Activity的任务栈设置为其创建的前面创建的task
    • 如果存在可以复用的TaskRecord,则将目标Activity的任务栈设置为其可以复用的任务栈

    2.10.2 AS.setTaskFromSourceRecord

      进入此分支的前提是mSourceRecord不为null,即发起端为Activity,此时会直接把目标ActivityRecord绑定到启动者的TaskRecord上

    //[ActivityStarter.java]
        private int setTaskFromSourceRecord() {
    
    		//获取启动着的任务栈
            final TaskRecord sourceTask = mSourceRecord.task;
    
    		//此时的发起端Actiivty所在的TaskRecord就是处于sourceStack栈顶,所以sourceStack.topTask就是要启动的Activity所在的栈
            //如果目标Activity不允许在屏幕上显示或者源任务栈和目标任务不在同一个栈
            final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
            if (moveStackAllowed) {
    			//获取当前要启动activity所属的ActivityStack栈
                mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
                        mOptions);
            }
    
            if (mTargetStack == null) {//目标ActivityStack为空
                mTargetStack = sourceTask.stack;
            } else if (mTargetStack != sourceTask.stack) {
             	//把启动方的任务栈绑定到目标ActivityStack上
                mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
                        ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
            }
            if (mDoResume) {
                mTargetStack.moveToFront("sourceStackToFront");
            }
    
    		//获取目标ActivityStack的顶部task
            final TaskRecord topTask = mTargetStack.topTask();
    
    		//发起端任务栈移动到ActivityStack的顶部,也就是设置为焦点
            if (topTask != sourceTask && !mAvoidMoveToFront) {
                mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
                        mStartActivity.appTimeTracker, "sourceTaskToFront");
            }
    
    		 //如果目标activity还没有加入到栈中,而且启动标志设置了CLEAR_TOP,那么我们将Activity添加到已经存在的任务栈中,并调用clear方法清空对应的activity
            if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
                // In this case, we are adding the activity to an existing task, but the caller has
    
                ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
                mKeepCurTransition = true;
                if (top != null) {
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, top.task);
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
    
                    mTargetStack.mLastPausedActivity = null;
                    if (mDoResume) {
                        mSupervisor.resumeFocusedStackTopActivityLocked();
                    }
                    ActivityOptions.abort(mOptions);
                    return START_DELIVERED_TO_TOP;
                }
            } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
                if (top != null) {
                    final TaskRecord task = top.task;
                    task.moveActivityToFrontLocked(top);
                    top.updateOptionsLocked(mOptions);
                    ActivityStack.logStartActivity(AM_NEW_INTENT, mStartActivity, task);
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
                    mTargetStack.mLastPausedActivity = null;
                    if (mDoResume) {
                        mSupervisor.resumeFocusedStackTopActivityLocked();
                    }
                    return START_DELIVERED_TO_TOP;
                }
            }
    
             //将Activity添加到相应的Task
            mStartActivity.setTask(sourceTask, null);
            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
                    + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
            return START_SUCCESS;
        }
    

    我们对该流程简单的分析一下,感觉这来来回回的绕着圈好难啊!

    • 要启动得Activity栈的顶部TaskRecord和启动方的TaskRecord不一致,则需要移动到其他的ActivityStack去显示。这里会通过AS.getLaunchStack从有效的displayId中去查找对应的ActivityStack。
    • 如果目标ActivityStack为空,这种属于默认的情况。会设置为启动方的ActivityStack。如果目标ActivityStack存在而且和启动方的ActivityStack不一致,则把启动方的任务栈(TaskRecord)绑定到目标所在的ActivityStack上
    • 把目标ActivityStack移动到最前方,同时也移到ActivityDisplay集合的顶部。
    • 最后一种情况AddingToTask为false,打开FLAG_ACTIVITY_CLEAR_TOP,则清除启动方的TaskRecord中的顶部。顶部不为空,则调用newIntent,再根据需要调用resume方法。
    • 最后调用mStartActivity.setTask将Activity添加到相应的Task

    对于上述的各种流程,小伙们能搞懂是最好了,搞不懂也没有关系,不影响Activity的整体启动。

    2.10.3 AS.setTaskFromInTask

      进入此分支的前提是mInTask不为null,即指定了目标Task

    //[ActivityStarter.java]
    	//将目标Activity的任务栈设置为mInTask
        private int setTaskFromInTask() {
            if (mLaunchBounds != null) {
                mInTask.updateOverrideConfiguration(mLaunchBounds);
                int stackId = mInTask.getLaunchStackId();
                if (stackId != mInTask.stack.mStackId) {
                    final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
                            mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
                    stackId = stack.mStackId;
                }
                if (StackId.resizeStackWithLaunchBounds(stackId)) {
                    mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
                }
            }
    
    		//根据实际情况检查是需要创建新的activity还是重新使用任务栈顶部的activity
            mTargetStack = mInTask.stack;
    		//将mInTask移动到顶部
            mTargetStack.moveTaskToFrontLocked(
                    mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
    
    		//获取指定任务栈顶Activity
            ActivityRecord top = mInTask.getTopActivity();
            if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
    			//如果设置了singleTop或者启动模式为singleTop或者singleTask,那么调用newIntent方法
    			if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
                        || mLaunchSingleTop || mLaunchSingleTask) {
                    ActivityStack.logStartActivity(AM_NEW_INTENT, top, top.task);
                    if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
                        return START_RETURN_INTENT_TO_CALLER;
                    }
                    top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
                    return START_DELIVERED_TO_TOP;
                }
            }
    
    		//mAddingToTask是标记位,标记着是否需要将Activity添加到TaskRecord中,
    		// 在之前进行如果已经将目标Activity放入到任务栈的话,这里就不需要再次放入了,
    		//只需要把TaskRecord移动ActivityStack顶部即可
            if (!mAddingToTask) {
                // We don't actually want to have this activity added to the task, so just
                // stop here but still tell the caller that we consumed the intent.
                ActivityOptions.abort(mOptions);
                return START_TASK_TO_FRONT;
            }
    
    		//将Activity添加到mInTask任务栈中
            mStartActivity.setTask(mInTask, null);
            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                    "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
    
            return START_SUCCESS;
        }
    

    好吗,这里的setTaskFromInTask方法也针对不同的情况分别进行了处理:

    • 如果mInTask的顶部和我们要启动的Activity相同,而且启动了singleTop或者singleTask,那么就直接调用newIntent方法。
    • 如果acitivity在之前的操作中已经添加到mInTask中了,那么这里只需要将mInTask移动到其所在ActivityStack的顶部即可。
    • 剩下的情况就需要将mInTask移动到ActivityStack的顶部,然后Activity添加到mInTask任务栈中。

    2.10.4 AS.setTaskToCurrentTopOrCreateNewTask

      尼玛终于只有最好的一种情况了

    	//查找当前焦点的ActivityStack上栈顶的Task,或者创建一个新的任务栈
        private void setTaskToCurrentTopOrCreateNewTask() {
        	//获取持有焦点的ActivityStack
            mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
                    mOptions);
            if (mDoResume) {
                mTargetStack.moveToFront("addingToTopTask");
            }
    		//获取栈顶的ActivityRecord,也就是会被我们覆盖的那个Activity
            final ActivityRecord prev = mTargetStack.topActivity();
    
    		//尝试从持有焦点的ActivityRecord获取其顶部的任务栈,如果获取不到的话,则创建一个
            final TaskRecord task = (prev != null) ? prev.task : mTargetStack.createTaskRecord(
                            mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
                            mStartActivity.info, mIntent, null, null, true);
    		//将activity添加到任务栈中
            mStartActivity.setTask(task, null);
            mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                    "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
        }
    

    尼玛此时此刻,actvity及其对应的task位置已经安排妥当,现在可以准备让这个activity开始工作了,真不容易啊!不容易啊!


    2.11 AS.startActivityUnchecked未完成之使命ActiviytStack.startActivityLocked

    //[ActivityStarter.java]
    	/*	这里的sourceRecord是指发起调用者
    		r是指本次的将要启动的Activity,startFlags取值为0,
    		doResume的值为true
    	*/
        private int startActivityUnchecked(final ActivityRecord r, 
        									ActivityRecord sourceRecord,
                							IVoiceInteractionSession voiceSession, 
                							IVoiceInteractor voiceInteractor,
                							int startFlags, boolean doResume, 
                							ActivityOptions options, 
                							TaskRecord inTask) {
            ...    								
    		//把当前启动的Activity加入TaskRecord以及绑定WindowManagerService
             mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
    		...          							
    }
    

      本来是打算将前面第二章节涉及的两大部分都讲述完毕,但是一看现在的这个文字量看来只能将第一大部分分析完成了,我们接着继续

    //[ActivityStack.java]
       final void startActivityLocked(
       				ActivityRecord r, //待启动的ActivityRecord
       				boolean newTask, //是否需要在新的任务中启动Activity
       				boolean keepCurTransition,//是否需要立即显示Activity。有些需要Pending的Activity,该值为false;对于初次对于此处而言,该值为true
                	ActivityOptions options
                	) {
    		//rTask即之前创建的TaskRecord,或者为查找到的可复用的TaskRecord
            TaskRecord rTask = r.task;
            final int taskId = rTask.taskId;//获取taskid
    
    		//表示宿主栈ActivityStack中没有历史任务,或者强制要求在新的任务中启动Activity
    		// 既然是一个新任务,那么就需要需要将任务插入宿主栈顶
            if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
                insertTaskAtTop(rTask, r);//插入新创建或复用的TaskRecord到栈顶
                mWindowManager.moveTaskToTop(taskId);//同时在Windowmanager中也移动到栈顶
            }
            TaskRecord task = null;
            // 进入该条件,表示需要在一个已有的任务中启动Activity
            // 先设置一个标志位,表示是否需要启动Activity,默认当然是要显示;
            // 但是当目标任务之上有全屏的Activity时,该标志位被置为false
            if (!newTask) {//这是表示存在复用的TaskRecord
                boolean startIt = true;
    			//遍历TaskRecord从这儿也可以得出TaskRecord在ActivityStack是以栈的方式管理的
    			//因为此时是倒序遍历的,即从上往下遍历宿主栈中的所有任务,找到目标任务的位置
                for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                    task = mTaskHistory.get(taskNdx);
                    if (task.getTopActivity() == null) {
                        continue;
                    }
                    if (task == r.task) {//在Task堆栈中找到了复用的Task
                        if (!startIt) {
                            task.addActivityToTop(r);//把当前启动的Activity加入到复用的Task栈顶
                            r.putInHistory();
                            addConfigOverride(r, task);//绑定到windowmanager中,此处很重要,但是不会在此分析
                            if (VALIDATE_TOKENS) {
                                validateAppTokensLocked();
                            }
                            ActivityOptions.abort(options);
                            return;
                        }
                        break;
                    } else if (task.numFullscreen > 0) {
                    	// 如果目标任务之上的某个任务包含全屏显示的Activity,则不需要显示目标Activity
                        startIt = false;
                    }
                }
            }
    
    
            if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
                mStackSupervisor.mUserLeaving = false;
                if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                        "startActivity() behind front, mUserLeaving=false");
            }
    
    	   // 以上完成的操作就是将待显示的任务放到了宿主栈的栈顶位置,
    	   // 接下来,需要将待显示的ActivityRecord放到任务的栈顶
            task = r.task;
            //当前启动的Activity加到所属Task栈顶中
            task.addActivityToTop(r);
            // 将一个新的ActivityRecord添加到任务栈顶后,需要重新调整FrontOfTask
            task.setFrontOfTask();
    	
            r.putInHistory();// 标记目标ActivityRecord已经放置到目标栈中
    		   /*
    		      如果当前ActivityStack不为 HomeStack,或者该ActivityStack中activity个数不为0,即宿主栈中已经有Activity
    		  */
            if (!isHomeStack() || numActivities() > 0) {
                boolean showStartingIcon = newTask;
                ProcessRecord proc = r.app;
                if (proc == null) {
                    proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
                }
                //对于刚启动HOME应用时,表示进程ProcessReocrd还为空
                if (proc == null || proc.thread == null) {
                    showStartingIcon = true;
                }
    
                if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                    mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
                    mNoAnimActivities.add(r);
                } else {
                    mWindowManager.prepareAppTransition(newTask
                            ? r.mLaunchTaskBehind
                                    ? TRANSIT_TASK_OPEN_BEHIND
                                    : TRANSIT_TASK_OPEN
                            : TRANSIT_ACTIVITY_OPEN, keepCurTransition);
                    mNoAnimActivities.remove(r);
                }
                //当前启动的Activity绑定到WIndowManagerService当中
                addConfigOverride(r, task);
                boolean doShow = true;
                if (newTask) {
                    if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                        resetTaskIfNeededLocked(r, r);
                        doShow = topRunningNonDelayedActivityLocked(null) == r;
                    }
                } else if (options != null && options.getAnimationType()
                        == ActivityOptions.ANIM_SCENE_TRANSITION) {
                    doShow = false;
                }
                if (r.mLaunchTaskBehind) {
                    mWindowManager.setAppVisibility(r.appToken, true);
                    ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                } else if (SHOW_APP_STARTING_PREVIEW && doShow) {
                    ActivityRecord prev = r.task.topRunningActivityWithStartingWindowLocked();
                    if (prev != null) {
                        if (prev.task != r.task) {
                            prev = null;
                        }
                        // (2) The current activity is already displayed.
                        else if (prev.nowVisible) {
                            prev = null;
                        }
                    }
                    r.showStartingWindow(prev, showStartingIcon);
                }
            } else {
            	// 进入该分支,表示当前的ActivityStack中还没有任何Activity,则不需要设置任何Activity启动相关的动画
            	// 只是将待启动的Activity绑定到窗口上
                addConfigOverride(r, task);
                ActivityOptions.abort(options);
                options = null;
            }
            if (VALIDATE_TOKENS) {
                validateAppTokensLocked();
            }
        }
    
        void addConfigOverride(ActivityRecord r, TaskRecord task) {
            final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
           // 将待启动的Activity绑定到窗口上
            mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                    r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                    (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
                    task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
                    task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
                    r.appInfo.targetSdkVersion);
            r.taskConfigOverride = task.mOverrideConfig;
        }
    

    该方法的主要主要执行如下的两大逻辑:

    • 将ActivityRecord放到目标任务的栈顶位置。注意,这里有两个栈顶位置:一个是ActivityRecord在TaskRecord中的位置,另一个是TaskRecord在ActivityStack中的位置。前一个是肯定的,但后一个,还得根据实际的情况决定

    • 将待启动的ActivityRecord绑定到了一个窗口。与此同时,Activity启动的动画也在此设置。为了省略分之细节,所以与WMS交互的窗口操作逻辑就不放出来了

    总之经过以上的重重步骤,此时目标Activity对应的Task也创建了,也把当前启动的Activity加入到Task正确的位置,ActivityStack也移动到了正确位置。此时本章节就分析到这里了!



    小结

      阅读源码是很操蛋的事情,同样的如果将太多的逻辑放在一篇中我想小伙们也会阅读起来也会操蛋,失去耐心的的,所以本篇章就先到这里了。分析至此我们对前面的篇章做一个小结,我们前面主要干了如下相关的事情:

    • 初始化Activity启动状态
    • 计算launchFlag
    • 计算调用者的ActivityStack
    • 检查是否存在复用的TaskRecord
    • 对于存在复用的TaskRecord则进行相应的ActivityStack、TaskRecord的移动(说实话,我也没有真的搞懂,希望这块比较有经验的小伙们能和我一起学习)
    • 计算当前启动Activity所属的TaskRecord
    • 把当前启动的Activity放到所属TaskRecord的栈顶

    并且通过前面的博文分析,小伙们心里应该有了如下的知识图谱:

    • 一个ActivityRecord对应一个Activity,保存了一个Activity的所有信息;但是一个Activity可能会有多个ActivityRecord,因为Activity可以被多次启动,这个主要取决于其启动模式,即二者不是一对一的关系,ActivityRecord如果存在一对一的关系,那么也只能说相对于Applicatiion而言
    • 一个TaskRecord由一个或者多个ActivityRecord组成,这就是我们常说的任务栈,具有后进先出的特点。
    • ActivityStack则是用来管理TaskRecord的,包含了多个TaskRecord。
    • singleTask 和 singleTop 模式的都会去任务栈中遍历寻找是否已经启动了相应实例
    • ActivityStackSupervisor 用来管理 ActivityStack 的,APP与 ActivityStack 之间并无必然的联系,这个要根据实际情况来看。有可能是一个APP对应一个 ActivityStack ,有可能是一个APP对应多个 ActivityStack ,也有可能是多个APP共用一个 ActivityStack
    • 并且启动模式如果intent中的和mainfest中的冲突,那么manfest的启动模式优先

    好了本篇博客真的只能到此了,虽然本人耗费了很多的时间来对Activity启动涉及的Task和ActivityStack等调度相关的知识点来进行分析和讲解,但是这其中牵涉的东西太多了,并且由于个人能力有限,自我感觉依然分析的不是很清晰,只能大伙见谅了。如果小伙们喜欢欢迎点赞或者能和我讨论关于本篇的知识点!如果小伙们对Activity的启动过程中Task和Stack还有疑问的,可以参见博客Activity启动流程(三)-Activity Task调度算法复盘分析,在该篇中会以实际案例出发来阐述Task和Stack相关的调度情况!

    参考博客:
    https://www.lizenghai.com/archives/94931.html#getReusableIntentActivity_Activity

    展开全文
  • 深入理解Activity启动流程(一)--Activity启动的概要流程深入理解Activity启动流程(二)--Activity启动相关类的类图深入理解Activity启动流程(三)--Activity启动的详细流程2深入理解Activity启动流程(四)--Activity ...
  • Activity启动流程比较复杂, 涉及的类及代码都很多, 本文侧重从整体流程描述这个过程,给出关键节点,尽量少的涉及代码细节。 啥也不说了,先上图。 在看本文的内容时, 可以参照此图片进行阅读。 ...
  • Android Activity启动过程

    千次阅读 2018-08-20 20:52:51
    在Android系统中,有两种操作会引发Activity的启动,一种用户点击应用程序图标时,Launcher会为我们启动应用...应用程序的默认Activity启动起来后,它又可以在内部通过调用startActvity接口启动新的Activity,依...
  • Activity启动过程涉及到的比较多的知识点有Binder的跨进程通讯,建议先看完Binder的跨进程通讯再来阅读本篇文章,在文章阅读开始,我们先要理解Activity启动模型,再者去理解有关Activity启动的基本概念,梳理...
  • 从log可以看出,当前Activity启动另一个Activity时,总是要等到另一个Activity的onResume方法走完才会返回当前Activity的生命周期继续执行,这是因为Activity的onResume执行完毕才算创建完成。当返回当前Activity时...
  • 老罗Activity启动流程总结

    千次阅读 2018-05-09 21:28:14
    Activity的启动流程我们可以将Activity划分为两种类型,根Activity和子Activity。... 子Activity:由根Activity或其他字Activity启动,他们有可能与启动他们的Activity运行在同一个进程中,也可能运行在不同的进程中。
  • 浅谈Activity启动流程

    千次阅读 2019-05-07 20:09:47
    概述 Activity的启动方式有两种,一种是显式的,一种是隐式的。 而且,启动的Activity和...Activity启动之前的一些事情 init进程:init是所有linux程序的起点,是Zygote的父进程。解析init.rc孵化出Zygote进程。 ...
  •     Activity启动流程源码实现(七)初始化目标Activity Android四大组件源码实现详解系列博客目录: Android应用进程创建流程大揭秘 Android四大组件之bindService源码实现详解 Android四大组件之Activity启动...
  • Android 8.0 Activity启动流程分析

    千次阅读 2020-01-18 15:33:13
    Activity启动过程中需要注意的一些类: Instrumentation 完成对Application和Activity初始化和生命周期调用的工具类。用来监控系统与应用的交互。 ActivityThread 管理应用进程的主线程的执行。 ...
  • Activity启动模式详解

    千次阅读 2016-08-09 19:15:52
    Activity启动模式详解对应的试验在这 http://blog.csdn.net/Ash_Zheng/article/details/52165402Activity的启动模式实际上是定义了Activity实例与当前Task的关联方式。所以想要清楚的了解Activity的启动模式,首先得...
  • Android基础中的Activity启动模式非常重要 本文将介绍对Activity启动模式进行全面介绍 目录1. 定义即Activity启动的方式2. 启动模式的类别Android启动提供了四种启动方式: 标准模式(standard) 栈顶复用模式...
  • Activity启动大致流程: 无论是通过Launcher来启动Activity,还是通过Activity内部调用startActivity接口来启动新的Activity,都通过Binder进程间通信进入到ActivityManagerService进程中,并且调用ActivityManager...
  • activity启动流程简述

    千次阅读 2017-05-26 20:17:46
    Activity是Android四大组件中唯一与用户...由于Activity启动过程复杂,代码量大,这里就不贴代码了,直接写调用的函数和作用. 发起进程: Activity.startActivity() Instrumentation.execStartActivity() 调用标准语句A
  • Android -- Activity启动流程分析

    千次阅读 2017-09-18 22:35:11
    Android -- Launcher中启动应用Activity的流程分析 Activity是Apk向用户提供交互界面的接口,它应该是我们平时最常见、最...本文我们侧重分析Activity启动的流程,来了解Activity启动过程中,系统到底做了哪些处理。
  • activity启动时间测试

    千次阅读 2017-07-27 17:00:34
    在进行性能测试的时候,通常需要测试一个activity的启动...1. 用命令得到activity启动/切换时间  1)获取你需要测试的activity名称(可以用hierarchy查看activity名称,或者用命令adb shell dumpsys activity 
  • Activity启动流程源码分析
  • Activity有很多Flag ,一些Flag可以用来设置启动模式,一些可以用来影响Activity的运行状态,这里介绍常见的FLAG 一般通过在Intent设置: ...一、更改Activity启动模式 FLAG_ACTIVITY_NEW_TASK ...
  • android 面试Activity启动流程

    千次阅读 2018-07-18 18:27:20
    市场上对Activity启动这块分析的文章很多,但是面试过程中简短的描述就需要很熟悉源码并且用精炼的语言描述出来。先看下大佬是怎么回答这个问题的: Activity的启动过程,我们可以从Context的startAct...
  • 优化Activity启动速度的另类解法

    千次阅读 2018-07-29 12:48:45
    今天来给大家分享一个性能优化的经验,主要在Activity启动方面。 众所周知,给用户即时的响应是增强移动设备用户体验的重要一环,而Activity在启动过程中,又会经历至少onCreate(), onStart(), onResume()这三个回...
  • activity启动流程

    千次阅读 2012-11-24 16:44:58
    再有一个是以类图的方式展现的activity启动的流程,可以看到各个类的主要作用 主要函数 分析: startActivityLocked 1、 getRecordForAppLocked获取调用者的相关信息保存到ProcessRecord变量,这里传递的...
  • Activity启动流程 1、首先从Activity类的startActivity()方法开始: @Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -...
  • 深入理解Activity启动流程

    千次阅读 2016-04-14 09:54:13
    深入理解Activity启动流程(一)–Activity启动相关类的类图 Activity启动时的概要交互流程 用户从Launcher程序点击应用图标可启动应用的入口Activity,Activity启动时需要多个进程之间的交互,Android系统中...
  • Activity启动模式

    千次阅读 2018-11-04 17:10:22
    一,启动模式分类: Standard(标准模式,默认) SingleTop(栈顶复用模式) SingleTask(栈内复用模式) SingleInstance(单实例模式) 通过AndroidManifest可配置Activity的LaunchMode.如果没有配置,默认是...
  •     Android四大组件之Activity启动流程源码实现详解一 前言   一直在筹划着写一个系列的博客关于Activity启动流程的详解,但是一直自我感觉功力不够!这是因为Activity的启动涉及到非常多的逻辑,其启动...
  • Android9.0 Activity启动流程分析(一)

    千次阅读 2018-12-05 15:41:09
    一、am命令 我们将利用am命令启动一个Activity,来分析Activity的启动...-W:表示等待目标activity启动的返回结果 -n :后接component name用于指定启动的Activity 在shell中输入如上命令之后会得到如下返回结果...
  • 前言 熟悉Activity的启动流程和运行原理是一个合格的应用开发人员所应该具备的基本素质,...本文基于Android 9.0版本源码,从Activity启动方法startActivity为切入口分析整个流程。 一、发出启动请求 启动一个A...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 273,246
精华内容 109,298
关键字:

activity启动