Android ActivityManagerService(AMS)的Activity管理

Android ActivityManagerService(AMS)的Activity管理

标签: androidAMSactivity
1084人阅读 评论(1) 收藏 举报
分类:

目录(?)[+]

对于AMS来讲,Activity管理是它的核心工作,前面两篇文章都是讲AMS的启动流程和进程的管理,这两篇文章其实是为本文做铺垫的,只有理解了前面两篇文章才能更好地理解AMS的activity管理。在谈到Activity的管理的时候,就不得不说一下Activity的启动流程,说道activity的启动流程就要说一下进程启动的问题了,前面一片文章中我们已经分析了AMS的进程管理,这里需要补充的一点就是在android中并没有针对app开放进程的启动接口,只是在启动activity或者service等组件的时候,我们的AMS会根据需要来启动相应的进程。
好了,下面我们开始分析AMS的activity的启动流程吧。

AMS的activity的启动流程

Activity的启动是从app端开始的,在AMS实际启动完成后结束的,这里就涉及到了Binder的C/S通讯,因此这里我们分为两个部分分析:客户端和服务端的实现。

activity启动之客户端

这里我们以在app中通过调用activity的startActivity方法启动目标activity来分析一个典型的activity启动流程。首先我们需要看一下Activity的startActivity方法的实现,Activity的startActivity实现了多态,一共两个实现:一个参数(intent)的,两个参数的(一个intent和一个bundle)的,不过通常我们都是调用一个参数的,下面是一个参数的实现:
startActivity@Activity.java

<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startActivity</span>(Intent intent) {
    <span class="hljs-keyword">this</span>.startActivity(intent, <span class="hljs-keyword">null</span>);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

可以看到这里还是调用了两个参数的:

<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startActivity</span>(Intent intent, @Nullable Bundle options) {
    <span class="hljs-keyword">if</span> (options != <span class="hljs-keyword">null</span>) {
        startActivityForResult(intent, -<span class="hljs-number">1</span>, options);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// Note we want to go through this call for compatibility with</span>
        <span class="hljs-comment">// applications that may have overridden the method.</span>
        startActivityForResult(intent, -<span class="hljs-number">1</span>);
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

我们发现这里调用了startActivityForResult方法,这个方法根据option的不同调用startActivityForResult方法时参数不一样,我们前面给的option参数是null因此这里走第一个分支:
startActivityForResult@Activity.java

<code class="hljs coffeescript has-numbering">public <span class="hljs-reserved">void</span> startActivityForResult(Intent intent, int requestCode, <span class="hljs-property">@Nullable</span> Bundle options) {
    <span class="hljs-keyword">if</span> (mParent == <span class="hljs-literal">null</span>) {
        <span class="hljs-regexp">//</span> 通过mInstrumentation的execStartActivity实际启动activity
        Instrumentation.ActivityResult ar =
            mInstrumentation.execStartActivity(
                <span class="hljs-keyword">this</span>, mMainThread.getApplicationThread(), mToken, <span class="hljs-keyword">this</span>,
                intent, requestCode, options);
        <span class="hljs-regexp">//</span> ar表示activity启动结果,如果结果就调用ActivityThread的sendActivityResult通知启动结果,这里会回调到请求activity的onActivityResult方法
        <span class="hljs-keyword">if</span> (ar != <span class="hljs-literal">null</span>) {
            mMainThread.sendActivityResult(
                mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                ar.getResultData());
        }
        <span class="hljs-keyword">if</span> (requestCode >= <span class="hljs-number">0</span>) {
            <span class="hljs-regexp">//</span> If <span class="hljs-keyword">this</span> start <span class="hljs-keyword">is</span> requesting a result, we can avoid making
            <span class="hljs-regexp">//</span> the activity visible <span class="hljs-keyword">until</span> the result <span class="hljs-keyword">is</span> received.  Setting
            <span class="hljs-regexp">//</span> <span class="hljs-keyword">this</span> code during onCreate(Bundle savedInstanceState) <span class="hljs-keyword">or</span> onResume() will keep the
            <span class="hljs-regexp">//</span> activity hidden during <span class="hljs-keyword">this</span> time, to avoid flickering.
            <span class="hljs-regexp">//</span> This can only be done <span class="hljs-keyword">when</span> a result <span class="hljs-keyword">is</span> requested because
            <span class="hljs-regexp">//</span> that guarantees we will get information back <span class="hljs-keyword">when</span> the
            <span class="hljs-regexp">//</span> activity <span class="hljs-keyword">is</span> finished, <span class="hljs-literal">no</span> matter what happens to it.
            mStartedActivity = <span class="hljs-literal">true</span>;
        }

        cancelInputsAndStartExitTransition(options);
        <span class="hljs-regexp">//</span> TODO Consider clearing/flushing other event sources <span class="hljs-keyword">and</span> events <span class="hljs-keyword">for</span> child windows.
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (options != <span class="hljs-literal">null</span>) {
            mParent.startActivityFromChild(<span class="hljs-keyword">this</span>, intent, requestCode, options);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-regexp">//</span> Note we want to go through <span class="hljs-keyword">this</span> method <span class="hljs-keyword">for</span> compatibility <span class="hljs-reserved">with</span>
            <span class="hljs-regexp">//</span> existing applications that may have overridden it.
            mParent.startActivityFromChild(<span class="hljs-keyword">this</span>, intent, requestCode);
        }
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul>

这里的关键就是通过mInstrumentation的execStartActivity实际启动activity部分了,我们看下Instrumentation的execStartActivity实现:
execStartActivity@Instrumentation.java

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> ActivityResult <span class="hljs-title">execStartActivity</span>(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, <span class="hljs-keyword">int</span> requestCode, Bundle options) {
    IApplicationThread whoThread = (IApplicationThread) contextThread;
    Uri referrer = target != <span class="hljs-keyword">null</span> ? target.onProvideReferrer() : <span class="hljs-keyword">null</span>;
    <span class="hljs-keyword">if</span> (referrer != <span class="hljs-keyword">null</span>) {
        intent.putExtra(Intent.EXTRA_REFERRER, referrer);
    }
    <span class="hljs-keyword">if</span> (mActivityMonitors != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">synchronized</span> (mSync) {
            <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> N = mActivityMonitors.size();
            <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i<N; i++) {
                <span class="hljs-keyword">final</span> ActivityMonitor am = mActivityMonitors.get(i);
                <span class="hljs-keyword">if</span> (am.match(who, <span class="hljs-keyword">null</span>, intent)) {
                    am.mHits++;
                    <span class="hljs-keyword">if</span> (am.isBlocking()) {
                        <span class="hljs-keyword">return</span> requestCode >= <span class="hljs-number">0</span> ? am.getResult() : <span class="hljs-keyword">null</span>;
                    }
                    <span class="hljs-keyword">break</span>;
                }
            }
        }
    }
    <span class="hljs-keyword">try</span> {
        intent.migrateExtraStreamToClipData();
        intent.prepareToLeaveProcess();
        <span class="hljs-comment">// 通过调用ActivityManagerNative的startActivity来实际启动activity</span>
        <span class="hljs-keyword">int</span> result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != <span class="hljs-keyword">null</span> ? target.mEmbeddedID : <span class="hljs-keyword">null</span>,
                    requestCode, <span class="hljs-number">0</span>, <span class="hljs-keyword">null</span>, options);
        checkStartActivityResult(result, intent);
    } <span class="hljs-keyword">catch</span> (RemoteException e) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failure from system"</span>, e);
    }
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li></ul>

这里我们看到execStartActivity方法最终也是通过调用ActivityManagerNative的startActivity来实际启动activity,ActivityManagerNative这个是一个Binder类,这个类提供了Binder通讯的实现用于和AMS通讯的,我们先看一下这个类的定义:

<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ActivityManagerNative</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Binder</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IActivityManager</span></span></code><ul style="" class="pre-numbering"><li>1</li></ul>

果不其然,这里继承自Binder类,并且实现了IActivityManager接口,下面我们来看下上面调用的getDefault方法的实现,看名字应该是一个单例实现:

<code class="hljs cs has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">public</span> IActivityManager <span class="hljs-title">getDefault</span>() {
   <span class="hljs-keyword">return</span> gDefault.<span class="hljs-keyword">get</span>();
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>

我们在看下gDefault:

<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Singleton<IActivityManager> gDefault = <span class="hljs-keyword">new</span> Singleton<IActivityManager>() {
    <span class="hljs-keyword">protected</span> IActivityManager <span class="hljs-title">create</span>() {
        IBinder b = ServiceManager.getService(<span class="hljs-string">"activity"</span>);
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">false</span>) {
            Log.v(<span class="hljs-string">"ActivityManager"</span>, <span class="hljs-string">"default service binder = "</span> + b);
        }
        IActivityManager am = asInterface(b);
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">false</span>) {
            Log.v(<span class="hljs-string">"ActivityManager"</span>, <span class="hljs-string">"default service = "</span> + am);
        }
        <span class="hljs-keyword">return</span> am;
    }
};</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

看到这里,想必大家都明白了,这的确是一个单例实现,其中g的意思应该是global的意思。Singleton泛型类的get方法会调用create方法来创建一个实例,我们一下这里的create的实现,首先通过SM获得AMS的IBinder对象(这个对象是用来和Binder发起通讯的对象),下面我们调用了asInterface方法将IBinder对象转换成IActivityManager,以方便客户端调用IActivityManager的接口。下面是asInterface的实现:

<code class="hljs cs has-numbering"><span class="hljs-keyword">static</span> <span class="hljs-keyword">public</span> IActivityManager <span class="hljs-title">asInterface</span>(IBinder obj) {
    <span class="hljs-keyword">if</span> (obj == <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
    }
    IActivityManager <span class="hljs-keyword">in</span> =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">in</span> != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">in</span>;
    }

    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ActivityManagerProxy(obj);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

如果你熟悉Binder的话,那么asInterface方法你应该很熟悉了,这个方法就是用来将IBinder对象转换成实际的Interface对象的,我们看到这里的原理很简单,首先查询本地有没有实现接口的服务,如果有就返回这个对象,这个时候表示操作和AMS是在同一个进程中的,显然很多情况下不是这样的,我们应该就是直接new一个ActivityManagerProxy对象,然后返回。ActivityManagerProxy类是ActivityManagerNative的一个内部类,是一个用来和AMS交互的proxy类。
现在我们明白了,我们上面的startActivity实际最后会调用到ActivityManagerProxy的startActivity中去:
startActivity@ActivityManagerProxy

<code class="hljs haskell has-numbering"><span class="hljs-title">public</span> int startActivity(<span class="hljs-type">IApplicationThread</span> caller, <span class="hljs-type">String</span> callingPackage, <span class="hljs-type">Intent</span> intent,
            <span class="hljs-type">String</span> resolvedType, <span class="hljs-type">IBinder</span> resultTo, <span class="hljs-type">String</span> resultWho, int requestCode,
            int startFlags, <span class="hljs-type">ProfilerInfo</span> profilerInfo, <span class="hljs-type">Bundle</span> options) throws <span class="hljs-type">RemoteException</span> {
    <span class="hljs-type">Parcel</span> <span class="hljs-typedef"><span class="hljs-keyword">data</span> = <span class="hljs-type">Parcel</span>.obtain<span class="hljs-container">()</span>;</span>
    <span class="hljs-type">Parcel</span> reply = <span class="hljs-type">Parcel</span>.obtain();
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInterfaceToken<span class="hljs-container">(<span class="hljs-type">IActivityManager</span>.<span class="hljs-title">descriptor</span>)</span>;</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeStrongBinder<span class="hljs-container">(<span class="hljs-title">caller</span> != <span class="hljs-title">null</span> ? <span class="hljs-title">caller</span>.<span class="hljs-title">asBinder</span>()</span> : null);</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeString<span class="hljs-container">(<span class="hljs-title">callingPackage</span>)</span>;</span>
    intent.writeToParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>, 0);</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeString<span class="hljs-container">(<span class="hljs-title">resolvedType</span>)</span>;</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeStrongBinder<span class="hljs-container">(<span class="hljs-title">resultTo</span>)</span>;</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeString<span class="hljs-container">(<span class="hljs-title">resultWho</span>)</span>;</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(<span class="hljs-title">requestCode</span>)</span>;</span>
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(<span class="hljs-title">startFlags</span>)</span>;</span>
    <span class="hljs-keyword">if</span> (profilerInfo != null) {
        <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(1)</span>;</span>
        profilerInfo.writeToParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>, <span class="hljs-type">Parcelable</span>.<span class="hljs-type">PARCELABLE_WRITE_RETURN_VALUE</span>);</span>
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(0)</span>;</span>
    }
    <span class="hljs-keyword">if</span> (options != null) {
        <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(1)</span>;</span>
        options.writeToParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>, 0);</span>
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-typedef"><span class="hljs-keyword">data</span>.writeInt<span class="hljs-container">(0)</span>;</span>
    }
    // 通过<span class="hljs-type">Binder</span>的transact方法开始和<span class="hljs-type">AMS</span>通讯。
    mRemote.transact(<span class="hljs-type">START_ACTIVITY_TRANSACTION</span>, <span class="hljs-typedef"><span class="hljs-keyword">data</span>, reply, 0);</span>
    reply.readException();
    int result = reply.readInt();
    reply.recycle();
    <span class="hljs-typedef"><span class="hljs-keyword">data</span>.recycle<span class="hljs-container">()</span>;</span>
    return result;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>

我们的ActivityManagerNative是一个强大的Binder实现类,这个类是一个既面向客户有面向服务端的类,它封装了Binder的通讯实现,减少客户端和服务端通讯的困难度。刚才我们说的ActivityManagerProxy内部类是运行在客户端的一个代理,他只是提供接口,真正的实现还是在服务端的,那么ActivityManagerNative就是运行在服务端的,他就是负责从Binder监听来自proxy代理的通讯请求,使用transaction code区别不同的信息,上面我们的transaction code就是START_ACTIVITY_TRANSACTION。在继续分析server端的实现之前,我们先来梳理一下client这边的操作,整体上如下面这个时序图:
这里写图片描述
同时我们还要弄清楚ActivityManagerNative,ActivityManagerProxy,AMS,IActivityManager以及我们后面要说道面向app的管理类:ActivityManager之间是什么关系,下面我们给出它的类图关系:
这里写图片描述
这张图描述了上面说到的一堆类和Binder之间的关系,看代码的话感觉关系比较乱,但是看这个图的话就基本明白了。下面我们就可以分析服务端的实现了。

activity启动之服务端

上面我们分析完了activity客户端的启动流程,下面我们继续看看服务端收到客户端的启动请求后是怎么处理的。上面我们说道ActivityManagerNative是运行在服务端的,专门用来处理客户端的通讯请求的,我们知道Binder驱动在收到数据后会返回给上层,上层的Binder会回调具体接受者的onTransact方法(如果你对Binder不熟悉的话,可以先学习一下Binder的知识,这在android世界里是很核心的一个东西,如果这个东西你不懂的话,那么android的大门永远你都进不了),下面我们看下ActivityManagerNative的onTransact实现:
onTransact@ActivityManagerNative.java

<code class="hljs haskell has-numbering">@<span class="hljs-type">Override</span>
<span class="hljs-title">public</span> boolean onTransact(int code, <span class="hljs-type">Parcel</span> <span class="hljs-typedef"><span class="hljs-keyword">data</span>, <span class="hljs-type">Parcel</span> reply, int flags)</span>
        throws <span class="hljs-type">RemoteException</span> {
    switch (code) {
    <span class="hljs-keyword">case</span> <span class="hljs-type">START_ACTIVITY_TRANSACTION</span>:
    {
        // 读取客户端的数据
        <span class="hljs-typedef"><span class="hljs-keyword">data</span>.enforceInterface<span class="hljs-container">(<span class="hljs-type">IActivityManager</span>.<span class="hljs-title">descriptor</span>)</span>;</span>
        <span class="hljs-type">IBinder</span> b = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readStrongBinder<span class="hljs-container">()</span>;</span>
        <span class="hljs-type">IApplicationThread</span> app = <span class="hljs-type">ApplicationThreadNative</span>.asInterface(b);
        <span class="hljs-type">String</span> callingPackage = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readString<span class="hljs-container">()</span>;</span>
        <span class="hljs-type">Intent</span> intent = <span class="hljs-type">Intent</span>.<span class="hljs-type">CREATOR</span>.createFromParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>);</span>
        <span class="hljs-type">String</span> resolvedType = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readString<span class="hljs-container">()</span>;</span>
        <span class="hljs-type">IBinder</span> resultTo = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readStrongBinder<span class="hljs-container">()</span>;</span>
        <span class="hljs-type">String</span> resultWho = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readString<span class="hljs-container">()</span>;</span>
        int requestCode = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readInt<span class="hljs-container">()</span>;</span>
        int startFlags = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readInt<span class="hljs-container">()</span>;</span>
        <span class="hljs-type">ProfilerInfo</span> profilerInfo = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readInt<span class="hljs-container">()</span> != 0</span>
                ? <span class="hljs-type">ProfilerInfo</span>.<span class="hljs-type">CREATOR</span>.createFromParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>) : null;</span>
        <span class="hljs-type">Bundle</span> options = <span class="hljs-typedef"><span class="hljs-keyword">data</span>.readInt<span class="hljs-container">()</span> != 0</span>
                ? <span class="hljs-type">Bundle</span>.<span class="hljs-type">CREATOR</span>.createFromParcel(<span class="hljs-typedef"><span class="hljs-keyword">data</span>) : null;</span>
        // 现在,数据读取完毕了,需要启动activity,调用startActivity实现
        int result = startActivity(app, callingPackage, intent, resolvedType,
                resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
        // 回写执行结果,通知客户端
        reply.writeNoException();
        reply.writeInt(result);
        return true;
    }
    ......(省略其他code的处理,我们现在只关心activity启动的code)</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li></ul>

这里我们调用了startActivity方法来启动activity,这个方法在AMS中实现的,因为ActivityManagerNative是一个抽象类没有实现,而AMS继承自ActivityManagerNative。我们看一下AMS中的startActivity:
startActivity@ActivityManagerService.java

<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> <span class="hljs-title">startActivity</span>(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, <span class="hljs-keyword">int</span> requestCode,
        <span class="hljs-keyword">int</span> startFlags, ProfilerInfo profilerInfo, Bundle options) {
    <span class="hljs-keyword">return</span> startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
        resultWho, requestCode, startFlags, profilerInfo, options,
        UserHandle.getCallingUserId());
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>

这里的startActivity是一个包装方法,它实际调用了startActivityAsUser方法,添加了一个参数UserHandle.getCallingUserId(),这个参数是通过Binder获取调用者的UID获得到的。
startActivityAsUser@ActivityManagerService.java

<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> <span class="hljs-title">startActivityAsUser</span>(IApplicationThread caller, String callingPackage,
        Intent intent, String resolvedType, IBinder resultTo, String resultWho, <span class="hljs-keyword">int</span> requestCode,
        <span class="hljs-keyword">int</span> startFlags, ProfilerInfo profilerInfo, Bundle options, <span class="hljs-keyword">int</span> userId) {
    <span class="hljs-comment">// 判断是不是一个独立的进程,独立进程是不允许调用startActivity方法的</span>
    enforceNotIsolatedCaller(<span class="hljs-string">"startActivity"</span>);
    <span class="hljs-comment">// 判断当前UID是否允许启动activity</span>
    userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
            <span class="hljs-keyword">false</span>, ALLOW_FULL_ONLY, <span class="hljs-string">"startActivity"</span>, <span class="hljs-keyword">null</span>);
    <span class="hljs-comment">// TODO: Switch to user app stacks here.</span>
    <span class="hljs-comment">// 调用ActivityStackSupervisor的startActivityMayWait方法启动activity</span>
    <span class="hljs-keyword">return</span> mStackSupervisor.startActivityMayWait(caller, -<span class="hljs-number">1</span>, callingPackage, intent,
            resolvedType, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, resultTo, resultWho, requestCode, startFlags,
            profilerInfo, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, options, <span class="hljs-keyword">false</span>, userId, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>

上面的代码首先进行安全检查,如果是独立进程就不允许启动activity,所谓的独立进程就是使用android:isolatedProcess标记的进程,该进程与系统其他部分隔离,且没有自己的权限。 与其通讯的唯一手段就是通过 Service API (绑定和启动)。接下来就是判断当前的UID是否有权限,如果安全检查通过的话,那么会调用ActivityStackSupervisor的startActivityMayWait方法启动activity,这个方法比较长,我们分段来分析:
startActivityMayWait@ActivityStackSupervisor.java

<code class="hljs java has-numbering"><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> startActivityMayWait(IApplicationThread caller, <span class="hljs-keyword">int</span> callingUid,
        String callingPackage, Intent intent, String resolvedType,
        IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
        IBinder resultTo, String resultWho, <span class="hljs-keyword">int</span> requestCode, <span class="hljs-keyword">int</span> startFlags,
        ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
        Bundle options, <span class="hljs-keyword">boolean</span> ignoreTargetSecurity, <span class="hljs-keyword">int</span> userId,
        IActivityContainer iContainer, TaskRecord inTask) {
    <span class="hljs-comment">// Refuse possible leaked file descriptors</span>
    <span class="hljs-keyword">if</span> (intent != <span class="hljs-keyword">null</span> && intent.hasFileDescriptors()) {
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"File descriptors passed in Intent"</span>);
    }

    <span class="hljs-comment">// 获得处理该intent的组件,</span>
    <span class="hljs-keyword">boolean</span> componentSpecified = intent.getComponent() != <span class="hljs-keyword">null</span>;

    <span class="hljs-comment">// Don't modify the client's object!</span>
    intent = <span class="hljs-keyword">new</span> Intent(intent);

    <span class="hljs-comment">// Collect information about the target of the Intent.</span>
    <span class="hljs-comment">// 解析intent中的目标信息</span>
    ActivityInfo aInfo =
            resolveActivity(intent, resolvedType, startFlags, profilerInfo, userId);</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

这里主要是通过resolveActivity来解析intent中包含的目标信息,存储在ActivityInfo对象当中,resolveActivity方法会会通过packageManagerService来解析当前intent包含的目标信息。
接下来的操作全部都是原子操作,我们继续看这个原子操作内部的代码:

<code class="hljs axapta has-numbering"><span class="hljs-keyword">if</span> (<span class="hljs-keyword">container</span> != <span class="hljs-keyword">null</span> && <span class="hljs-keyword">container</span>.mParentActivity != <span class="hljs-keyword">null</span> &&
                    <span class="hljs-keyword">container</span>.mParentActivity.state != RESUMED) {
    <span class="hljs-comment">// Cannot start a child activity if the parent is not resumed.</span>
    <span class="hljs-keyword">return</span> ActivityManager.START_CANCELED;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

这里是一个判断,意思是如果启动目标activity的请求activity还没有resume的话,那么它是不能启动一个新的activity的,也就是说如果一个activity还没有启动完成,那么它是不能启动一个新的activity的。

<code class="hljs java has-numbering"><span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> realCallingPid = Binder.getCallingPid();
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> realCallingUid = Binder.getCallingUid();
<span class="hljs-keyword">int</span> callingPid;
<span class="hljs-keyword">if</span> (callingUid >= <span class="hljs-number">0</span>) {
    callingPid = -<span class="hljs-number">1</span>;
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (caller == <span class="hljs-keyword">null</span>) {
    callingPid = realCallingPid;
    callingUid = realCallingUid;
} <span class="hljs-keyword">else</span> {
    callingPid = callingUid = -<span class="hljs-number">1</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

这里的操作比较简单,通过Binder获得caller的pid和uid,然后给callingPid和callingUid赋值,我们前面你传递进来的callingUid是-1,并且caller不为空,因此我们走最后一个分支,也就是callingPid和callingUid都是-1。

<code class="hljs avrasm has-numbering">if (aInfo != null &&
                    (aInfo<span class="hljs-preprocessor">.applicationInfo</span><span class="hljs-preprocessor">.privateFlags</span>
                            &ApplicationInfo<span class="hljs-preprocessor">.PRIVATE</span>_FLAG_CANT_SAVE_STATE) != <span class="hljs-number">0</span>) {
   // This may be a heavy-weight process!  Check to see if we already
   // have another, different heavy-weight process running.
   if (aInfo<span class="hljs-preprocessor">.processName</span><span class="hljs-preprocessor">.equals</span>(aInfo<span class="hljs-preprocessor">.applicationInfo</span><span class="hljs-preprocessor">.packageName</span>)) {
       if (mService<span class="hljs-preprocessor">.mHeavyWeightProcess</span> != null &&
               (mService<span class="hljs-preprocessor">.mHeavyWeightProcess</span><span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.uid</span> != aInfo<span class="hljs-preprocessor">.applicationInfo</span><span class="hljs-preprocessor">.uid</span> ||
               !mService<span class="hljs-preprocessor">.mHeavyWeightProcess</span><span class="hljs-preprocessor">.processName</span><span class="hljs-preprocessor">.equals</span>(aInfo<span class="hljs-preprocessor">.processName</span>))) {
           int appCallingUid = callingUid<span class="hljs-comment">;</span>
           if (caller != null) {
               ProcessRecord callerApp = mService<span class="hljs-preprocessor">.getRecordForAppLocked</span>(caller)<span class="hljs-comment">;</span>
               if (callerApp != null) {
                   appCallingUid = callerApp<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.uid</span><span class="hljs-comment">;</span>
               } else {
                   Slog<span class="hljs-preprocessor">.w</span>(TAG, <span class="hljs-string">"Unable to find app for caller "</span> + caller
                         + <span class="hljs-string">" (pid="</span> + callingPid + <span class="hljs-string">") when starting: "</span>
                         + intent<span class="hljs-preprocessor">.toString</span>())<span class="hljs-comment">;</span>
                   ActivityOptions<span class="hljs-preprocessor">.abort</span>(options)<span class="hljs-comment">;</span>
                   return ActivityManager<span class="hljs-preprocessor">.START</span>_PERMISSION_DENIED<span class="hljs-comment">;</span>
               }
           }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

上面的代码就是判断目标activity进程是不是重量级进程,如果当前系统中已经存在的重量级进程不是将要启动的这个,那么就要给intent重新赋值。
接下来的工作就是通过调用startActivityLocked方法来进一步完成启动工作,后面的outResult因为我们给的是null,因此不会执行。
现在我们来详细分析一下startActivityLocked的实现,由于这个函数比较长,我们就只关注重点部分的操作,同样的我们分步分析:
startActivityLocked@ActivityStackSupervisor.java

<code class="hljs bash has-numbering">ProcessRecord <span class="hljs-built_in">caller</span>App = null;
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">caller</span> != null) {
    <span class="hljs-built_in">caller</span>App = mService.getRecordForAppLocked(<span class="hljs-built_in">caller</span>);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">caller</span>App != null) {
        callingPid = <span class="hljs-built_in">caller</span>App.pid;
        callingUid = <span class="hljs-built_in">caller</span>App.info.uid;
    } <span class="hljs-keyword">else</span> {
        Slog.w(TAG, <span class="hljs-string">"Unable to find app for caller "</span> + <span class="hljs-built_in">caller</span>
              + <span class="hljs-string">" (pid="</span> + callingPid + <span class="hljs-string">") when starting: "</span>
              + intent.toString());
        err = ActivityManager.START_PERMISSION_DENIED;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

首先通过判断caller是不是为空确定调用者本身进程是不是存在的,否则就直接返回START_PERMISSION_DENIED,表示操作失败。这种情况是有可能会发生的,比如调用者被意外杀死,或者发生操作退出等等。

<code class="hljs coffeescript has-numbering"><span class="hljs-keyword">if</span> ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != <span class="hljs-number">0</span> && sourceRecord != <span class="hljs-literal">null</span>) {
    <span class="hljs-regexp">//</span> Transfer the result target from the source activity to the <span class="hljs-keyword">new</span>
    <span class="hljs-regexp">//</span> one being started, including any failures.
    <span class="hljs-keyword">if</span> (requestCode >= <span class="hljs-number">0</span>) {
        ActivityOptions.abort(options);
        <span class="hljs-keyword">return</span> ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
    }
    resultRecord = sourceRecord.resultTo;
    <span class="hljs-keyword">if</span> (resultRecord != <span class="hljs-literal">null</span> && !resultRecord.isInStackLocked()) {
        resultRecord = <span class="hljs-literal">null</span>;
    }
    resultWho = sourceRecord.resultWho;
    requestCode = sourceRecord.requestCode;
    sourceRecord.resultTo = <span class="hljs-literal">null</span>;
    <span class="hljs-keyword">if</span> (resultRecord != <span class="hljs-literal">null</span>) {
        resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
    }
    <span class="hljs-keyword">if</span> (sourceRecord.launchedFromUid == callingUid) {
        <span class="hljs-regexp">//</span> The <span class="hljs-keyword">new</span> activity <span class="hljs-keyword">is</span> being launched from the same uid as the previous
        <span class="hljs-regexp">//</span> activity <span class="hljs-keyword">in</span> the flow, <span class="hljs-keyword">and</span> asking to forward its result back to the
        <span class="hljs-regexp">//</span> previous.  In <span class="hljs-keyword">this</span> <span class="hljs-reserved">case</span> the activity <span class="hljs-keyword">is</span> serving as a trampoline between
        <span class="hljs-regexp">//</span> the two, so we also want to update its launchedFromPackage to be the
        <span class="hljs-regexp">//</span> same as the previous activity.  Note that <span class="hljs-keyword">this</span> <span class="hljs-keyword">is</span> safe, since we know
        <span class="hljs-regexp">//</span> these two packages come from the same uid; the caller could just as
        <span class="hljs-regexp">//</span> well have supplied that same package name itself.  This specifially
        <span class="hljs-regexp">//</span> deals <span class="hljs-reserved">with</span> the <span class="hljs-reserved">case</span> <span class="hljs-keyword">of</span> an intent picker/chooser being launched <span class="hljs-keyword">in</span> the app
        <span class="hljs-regexp">//</span> flow to redirect to an activity picked <span class="hljs-keyword">by</span> the user, where we want the final
        <span class="hljs-regexp">//</span> activity to consider it to have been launched <span class="hljs-keyword">by</span> the previous app activity.
        callingPackage = sourceRecord.launchedFromPackage;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>

这段代码是处理FLAG_ACTIVITY_FORWARD_RESULT标识的部分,FLAG_ACTIVITY_FORWARD_RESULT标识是一个跨越式传递的标记。比如Activity1启动了Activity2,但是Activity2启动Activity3的时候使用了这个标记,那么Activity3调用setResult的时候,result并不会想一般情况中的那样传递给Activity2,而是回传给Activity1.为了达到这个目的,只要caller修改为Activity1就可以了,上面的代码就是做这个工作的:替换caller。同时,因为在这个标记下,Activity2已经把result的目标对象设置为Activity1,因此它自身就不能再通过startActivityForResult来启动Activity3,否则就会报错:START_FORWARD_AND_REQUEST_CONFLICT。
接下来就会检查目标intent中的component是否为空,如果为空的话,就说明这个intent当目前为止还没有相应的class来handle它,这个时候需要退出;同样的,如果通过PMS解析还不能找到对应的类来处理的话,也是要终止操作的:

<code class="hljs cs has-numbering"><span class="hljs-keyword">if</span> (err == ActivityManager.START_SUCCESS && intent.getComponent() == <span class="hljs-keyword">null</span>) {
    <span class="hljs-comment">// We couldn't find a class that can handle the given Intent.</span>
    <span class="hljs-comment">// That's the end of that!</span>
    err = ActivityManager.START_INTENT_NOT_RESOLVED;
}

<span class="hljs-keyword">if</span> (err == ActivityManager.START_SUCCESS && aInfo == <span class="hljs-keyword">null</span>) {
    <span class="hljs-comment">// We couldn't find the specific class specified in the Intent.</span>
    <span class="hljs-comment">// Also the end of the line.</span>
    err = ActivityManager.START_CLASS_NOT_FOUND;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

接下来就执行权限判断,看下调用者是不是有权限启动任何activity:

<code class="hljs lasso has-numbering">boolean <span class="hljs-keyword">abort</span> <span class="hljs-subst">=</span> <span class="hljs-literal">false</span>;
final int startAnyPerm <span class="hljs-subst">=</span> mService<span class="hljs-built_in">.</span>checkPermission(
        START_ANY_ACTIVITY, callingPid, callingUid);

<span class="hljs-keyword">if</span> (startAnyPerm <span class="hljs-subst">!=</span> PERMISSION_GRANTED) {
    final int componentRestriction <span class="hljs-subst">=</span> getComponentRestrictionForCallingPackage(
            aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity);
    final int actionRestriction <span class="hljs-subst">=</span> getActionRestrictionForCallingPackage(
            intent<span class="hljs-built_in">.</span>getAction(), callingPackage, callingPid, callingUid);

    <span class="hljs-keyword">if</span> (componentRestriction <span class="hljs-subst">==</span> ACTIVITY_RESTRICTION_PERMISSION
            <span class="hljs-subst">||</span> actionRestriction <span class="hljs-subst">==</span> ACTIVITY_RESTRICTION_PERMISSION) {
        <span class="hljs-keyword">if</span> (resultRecord <span class="hljs-subst">!=</span> <span class="hljs-built_in">null</span>) {
            resultStack<span class="hljs-built_in">.</span>sendActivityResultLocked(<span class="hljs-subst">-</span><span class="hljs-number">1</span>,
                    resultRecord, resultWho, requestCode,
                    Activity<span class="hljs-built_in">.</span>RESULT_CANCELED, <span class="hljs-built_in">null</span>);
        }
        <span class="hljs-built_in">String</span> msg;
        <span class="hljs-keyword">if</span> (actionRestriction <span class="hljs-subst">==</span> ACTIVITY_RESTRICTION_PERMISSION) {
            msg <span class="hljs-subst">=</span> <span class="hljs-string">"Permission Denial: starting "</span> <span class="hljs-subst">+</span> intent<span class="hljs-built_in">.</span>toString()
                    <span class="hljs-subst">+</span> <span class="hljs-string">" from "</span> <span class="hljs-subst">+</span> callerApp <span class="hljs-subst">+</span> <span class="hljs-string">" (pid="</span> <span class="hljs-subst">+</span> callingPid
                    <span class="hljs-subst">+</span> <span class="hljs-string">", uid="</span> <span class="hljs-subst">+</span> callingUid <span class="hljs-subst">+</span> <span class="hljs-string">")"</span> <span class="hljs-subst">+</span> <span class="hljs-string">" with revoked permission "</span>
                    <span class="hljs-subst">+</span> ACTION_TO_RUNTIME_PERMISSION<span class="hljs-built_in">.</span>get(intent<span class="hljs-built_in">.</span>getAction());
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-subst">!</span>aInfo<span class="hljs-built_in">.</span>exported) {
            msg <span class="hljs-subst">=</span> <span class="hljs-string">"Permission Denial: starting "</span> <span class="hljs-subst">+</span> intent<span class="hljs-built_in">.</span>toString()
                    <span class="hljs-subst">+</span> <span class="hljs-string">" from "</span> <span class="hljs-subst">+</span> callerApp <span class="hljs-subst">+</span> <span class="hljs-string">" (pid="</span> <span class="hljs-subst">+</span> callingPid
                    <span class="hljs-subst">+</span> <span class="hljs-string">", uid="</span> <span class="hljs-subst">+</span> callingUid <span class="hljs-subst">+</span> <span class="hljs-string">")"</span>
                    <span class="hljs-subst">+</span> <span class="hljs-string">" not exported from uid "</span> <span class="hljs-subst">+</span> aInfo<span class="hljs-built_in">.</span>applicationInfo<span class="hljs-built_in">.</span>uid;
        } <span class="hljs-keyword">else</span> {
            msg <span class="hljs-subst">=</span> <span class="hljs-string">"Permission Denial: starting "</span> <span class="hljs-subst">+</span> intent<span class="hljs-built_in">.</span>toString()
                    <span class="hljs-subst">+</span> <span class="hljs-string">" from "</span> <span class="hljs-subst">+</span> callerApp <span class="hljs-subst">+</span> <span class="hljs-string">" (pid="</span> <span class="hljs-subst">+</span> callingPid
                    <span class="hljs-subst">+</span> <span class="hljs-string">", uid="</span> <span class="hljs-subst">+</span> callingUid <span class="hljs-subst">+</span> <span class="hljs-string">")"</span>
                    <span class="hljs-subst">+</span> <span class="hljs-string">" requires "</span> <span class="hljs-subst">+</span> aInfo<span class="hljs-built_in">.</span>permission;
        }
        Slog<span class="hljs-built_in">.</span>w(<span class="hljs-built_in">TAG</span>, msg);
        throw <span class="hljs-literal">new</span> SecurityException(msg);
    }

    <span class="hljs-keyword">if</span> (actionRestriction <span class="hljs-subst">==</span> ACTIVITY_RESTRICTION_APPOP) {
        <span class="hljs-built_in">String</span> message <span class="hljs-subst">=</span> <span class="hljs-string">"Appop Denial: starting "</span> <span class="hljs-subst">+</span> intent<span class="hljs-built_in">.</span>toString()
                <span class="hljs-subst">+</span> <span class="hljs-string">" from "</span> <span class="hljs-subst">+</span> callerApp <span class="hljs-subst">+</span> <span class="hljs-string">" (pid="</span> <span class="hljs-subst">+</span> callingPid
                <span class="hljs-subst">+</span> <span class="hljs-string">", uid="</span> <span class="hljs-subst">+</span> callingUid <span class="hljs-subst">+</span> <span class="hljs-string">")"</span>
                <span class="hljs-subst">+</span> <span class="hljs-string">" requires "</span> <span class="hljs-subst">+</span> AppOpsManager<span class="hljs-built_in">.</span>permissionToOp(
                        ACTION_TO_RUNTIME_PERMISSION<span class="hljs-built_in">.</span>get(intent<span class="hljs-built_in">.</span>getAction()));
        Slog<span class="hljs-built_in">.</span>w(<span class="hljs-built_in">TAG</span>, message);
        <span class="hljs-keyword">abort</span> <span class="hljs-subst">=</span> <span class="hljs-literal">true</span>;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (componentRestriction <span class="hljs-subst">==</span> ACTIVITY_RESTRICTION_APPOP) {
        <span class="hljs-built_in">String</span> message <span class="hljs-subst">=</span> <span class="hljs-string">"Appop Denial: starting "</span> <span class="hljs-subst">+</span> intent<span class="hljs-built_in">.</span>toString()
                <span class="hljs-subst">+</span> <span class="hljs-string">" from "</span> <span class="hljs-subst">+</span> callerApp <span class="hljs-subst">+</span> <span class="hljs-string">" (pid="</span> <span class="hljs-subst">+</span> callingPid
                <span class="hljs-subst">+</span> <span class="hljs-string">", uid="</span> <span class="hljs-subst">+</span> callingUid <span class="hljs-subst">+</span> <span class="hljs-string">")"</span>
                <span class="hljs-subst">+</span> <span class="hljs-string">" requires appop "</span> <span class="hljs-subst">+</span> AppOpsManager<span class="hljs-built_in">.</span>permissionToOp(aInfo<span class="hljs-built_in">.</span>permission);
        Slog<span class="hljs-built_in">.</span>w(<span class="hljs-built_in">TAG</span>, message);
        <span class="hljs-keyword">abort</span> <span class="hljs-subst">=</span> <span class="hljs-literal">true</span>;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li></ul>

如果权限不允许的话,就继续看是不是有权限启动intent中对应的组件(此时是activity)和目标app中对这个组件的权限是不是满足,如果两个都不满足就直接抛出SecurityException异常,终止操作。如果是目标进程不允许当前的操作的话,那么就把abort置为true。
我们继续看下面的代码:

<code class="hljs avrasm has-numbering">abort |= !mService<span class="hljs-preprocessor">.mIntentFirewall</span><span class="hljs-preprocessor">.checkStartActivity</span>(intent, callingUid,
        callingPid, resolvedType, aInfo<span class="hljs-preprocessor">.applicationInfo</span>)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>

这段代码通过intent防火墙来检查该intent是否可通过,intent防火墙是android 4.4.2中加入的一个安全机制,这个机制设计的目的就是要检查android中的intent的权限问题,可以通过配置位于/data/system/ifw/下的策略文件来阻止一些intent的发送。策略文件是一个xml文件,这个文件的格式基本如下:

<code class="hljs xml has-numbering"><span class="hljs-tag"><<span class="hljs-title">rules</span>></span>
  <span class="hljs-tag"><<span class="hljs-title">activity</span> <span class="hljs-attribute">block</span>=<span class="hljs-value">"[true/false]"</span> <span class="hljs-attribute">log</span>=<span class="hljs-value">"[true/false]"</span> ></span>
    <span class="hljs-tag"><<span class="hljs-title">intent-filter</span> ></span>
      <span class="hljs-tag"><<span class="hljs-title">path</span> <span class="hljs-attribute">literal</span>=<span class="hljs-value">"[literal]"</span> <span class="hljs-attribute">prefix</span>=<span class="hljs-value">"[prefix]"</span> <span class="hljs-attribute">sglob</span>=<span class="hljs-value">"[sglob]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">auth</span> <span class="hljs-attribute">host</span>=<span class="hljs-value">"[host]"</span> <span class="hljs-attribute">port</span>=<span class="hljs-value">"[port]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">ssp</span> <span class="hljs-attribute">literal</span>=<span class="hljs-value">"[literal]"</span> <span class="hljs-attribute">prefix</span>=<span class="hljs-value">"[prefix]"</span> <span class="hljs-attribute">sglob</span>=<span class="hljs-value">"[sglob]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">scheme</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"[name]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">type</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"[name]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">cat</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"[category]"</span> /></span>
      <span class="hljs-tag"><<span class="hljs-title">action</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"[action]"</span> /></span>
    <span class="hljs-tag"></<span class="hljs-title">intent-filter</span>></span>
    <span class="hljs-tag"><<span class="hljs-title">component-filter</span> <span class="hljs-attribute">name</span>=<span class="hljs-value">"[component]"</span> /></span>
  <span class="hljs-tag"></<span class="hljs-title">activity</span>></span>
<span class="hljs-tag"></<span class="hljs-title">rules</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>

更多关于intent防火墙的信息,可以查看:
http://www.cis.syr.edu/~wedu/android/IntentFirewall/
我们看到上面intent防火墙检查代码会把最后的结果和abort变量或运算,abort变量就表示着activity启动是不是需要继续:

<code class="hljs lasso has-numbering"><span class="hljs-keyword">if</span> (<span class="hljs-keyword">abort</span>) {
    <span class="hljs-keyword">if</span> (resultRecord <span class="hljs-subst">!=</span> <span class="hljs-built_in">null</span>) {
        resultStack<span class="hljs-built_in">.</span>sendActivityResultLocked(<span class="hljs-subst">-</span><span class="hljs-number">1</span>, resultRecord, resultWho, requestCode,
                Activity<span class="hljs-built_in">.</span>RESULT_CANCELED, <span class="hljs-built_in">null</span>);
    }
    <span class="hljs-comment">// We pretend to the caller that it was really started, but</span>
    <span class="hljs-comment">// they will just get a cancel result.</span>
    ActivityOptions<span class="hljs-built_in">.</span><span class="hljs-keyword">abort</span>(options);
    <span class="hljs-keyword">return</span> ActivityManager<span class="hljs-built_in">.</span>START_SUCCESS;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

这里如果需要结果就直接就发送一个RESULT_CANCELED结果,然后直接返回。否则就看下面的代码:

<code class="hljs axapta has-numbering">ActivityRecord r = <span class="hljs-keyword">new</span> ActivityRecord(mService, callerApp, callingUid, callingPackage,
        intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
        requestCode, componentSpecified, voiceSession != <span class="hljs-keyword">null</span>, <span class="hljs-keyword">this</span>, <span class="hljs-keyword">container</span>, options);
<span class="hljs-keyword">if</span> (outActivity != <span class="hljs-keyword">null</span>) {
    outActivity[<span class="hljs-number">0</span>] = r;
}

<span class="hljs-keyword">if</span> (r.appTimeTracker == <span class="hljs-keyword">null</span> && sourceRecord != <span class="hljs-keyword">null</span>) {
    <span class="hljs-comment">// If the caller didn't specify an explicit time tracker, we want to continue</span>
    <span class="hljs-comment">// tracking under any it has.</span>
    r.appTimeTracker = sourceRecord.appTimeTracker;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

这段代码主要就是生成一个ActivityRecord对象r,记录当前的各项判断结果。

<code class="hljs lasso has-numbering">final ActivityStack <span class="hljs-built_in">stack</span> <span class="hljs-subst">=</span> mFocusedStack;
<span class="hljs-keyword">if</span> (voiceSession <span class="hljs-subst">==</span> <span class="hljs-built_in">null</span> <span class="hljs-subst">&&</span> (<span class="hljs-built_in">stack</span><span class="hljs-built_in">.</span>mResumedActivity <span class="hljs-subst">==</span> <span class="hljs-built_in">null</span>
        <span class="hljs-subst">||</span> <span class="hljs-built_in">stack</span><span class="hljs-built_in">.</span>mResumedActivity<span class="hljs-built_in">.</span>info<span class="hljs-built_in">.</span>applicationInfo<span class="hljs-built_in">.</span>uid <span class="hljs-subst">!=</span> callingUid)) {
    <span class="hljs-keyword">if</span> (<span class="hljs-subst">!</span>mService<span class="hljs-built_in">.</span>checkAppSwitchAllowedLocked(callingPid, callingUid,
            realCallingPid, realCallingUid, <span class="hljs-string">"Activity start"</span>)) {
        PendingActivityLaunch pal <span class="hljs-subst">=</span>
                <span class="hljs-literal">new</span> PendingActivityLaunch(r, sourceRecord, startFlags, <span class="hljs-built_in">stack</span>);
        mPendingActivityLaunches<span class="hljs-built_in">.</span>add(pal);
        ActivityOptions<span class="hljs-built_in">.</span><span class="hljs-keyword">abort</span>(options);
        <span class="hljs-keyword">return</span> ActivityManager<span class="hljs-built_in">.</span>START_SWITCHES_CANCELED;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

这里检查启动activity是否会引起进程切换,如果需要的话,还要检查Android系统目前是否允许切换。什么情况不允许切换呢?最常见的例子就是打电话的时候,如果是位于通话界面的话,可以通过AMS的stopAppSwitches来禁止切换掉当前进程,电话结束后再调用resumeAppSwitches来恢复切换。需要注意的是,这个接口一般的普通的app是不能调用的,因此这个操作一定是系统app会操作的。

<code class="hljs bash has-numbering"><span class="hljs-keyword">do</span>PendingActivityLaunchesLocked(<span class="hljs-literal">false</span>);

err = startActivityUncheckedLocked(r, <span class="hljs-built_in">source</span>Record, voiceSession, voiceInteractor,
        startFlags, <span class="hljs-literal">true</span>, options, <span class="hljs-keyword">in</span>Task);</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

如果允许进程切换的话,这时需要调用doPendingActivityLaunchesLocked方法先处理所有pending状态的activity,然后再调用startActivityUncheckedLocked方法继续处理当前方法继续处理当前的activity。处于pending状态的activity也是通过startActivityUncheckedLocked实现的,现在我们来分析一下这个方法,这个方法比较长,我们分段分析:

<code class="hljs java has-numbering"><span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
<span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
<span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;

<span class="hljs-keyword">int</span> launchFlags = intent.getFlags();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

这是前期准备阶段,主要是获取activity的启动模式和启动标记信息,关于activity的启动模式可以参考我的博客Android升华之路——activity的启动模式关于activity启动标记,可以参考google的android api文档中的描述:
https://developer.android.com/reference/android/content/Intent.html
这个文档中主要讲解了所有的android中会用的启动flag,我们这里只关心activity启动相关的标记位,这些标记是以“FLAG_ACTIVITY”开头的,大家可以可以看看。如果大家对E文没有感觉的话,可以看热心网友翻译的(翻译中有个人理解):
http://blog.csdn.net/javensun/article/details/8700265
其中我们需要重点说明的几个标记位如下:
FLAG_ACTIVITY_NEW_DOCUMENT:我们的代码下面就要用到的,这个标记官网描述如下:
这里写图片描述
从描述中可以看出,这个标记位最好和documentLaunchMode启动一起使用,那么什么是 documentLaunchMode呢?大家可以查看这个官网链接:
https://developer.android.com/reference/android/R.attr.html#documentLaunchMode
这里就不详细解释了。大家只要知道这个标记是在android 5.0中引入的,专门用于控制处于overview screen的任务总览使用的,overview screen是在android 5.0界面的导航栏最右边的方形按钮按下会弹出的界面。这个界面将最近的任务以快照的形式呈现出来。
FLAG_ACTIVITY_NEW_TASK:这个是single task对应的标记位,表示activity启动后需要放在一个新的task栈中
剩下的标记位大家最好在分析代码的时候,一边查看api手册。
继续我们上面的代码分析,上面的代码获取了当前activity的启动模式和标记位,以方便后面的处理。Android中的众多启动标记位和启动模式都是在这个方法中处理的。

<code class="hljs avrasm has-numbering">if ((launchFlags & Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_DOCUMENT) != <span class="hljs-number">0</span> &&
                (launchSingleInstance || launchSingleTask)) {
    // We have a conflict between the Intent <span class="hljs-keyword">and</span> the Activity manifest, manifest wins.
    Slog<span class="hljs-preprocessor">.i</span>(TAG, <span class="hljs-string">"Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is "</span> +
            <span class="hljs-string">"\"singleInstance\" or \"singleTask\""</span>)<span class="hljs-comment">;</span>
    launchFlags &=
            ~(Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_DOCUMENT | Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_MULTIPLE_TASK)<span class="hljs-comment">;</span>
} else {
    switch (r<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.documentLaunchMode</span>) {
        case ActivityInfo<span class="hljs-preprocessor">.DOCUMENT</span>_LAUNCH_NONE:
            <span class="hljs-keyword">break</span><span class="hljs-comment">;</span>
        case ActivityInfo<span class="hljs-preprocessor">.DOCUMENT</span>_LAUNCH_INTO_EXISTING:
            launchFlags |= Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_DOCUMENT<span class="hljs-comment">;</span>
            <span class="hljs-keyword">break</span><span class="hljs-comment">;</span>
        case ActivityInfo<span class="hljs-preprocessor">.DOCUMENT</span>_LAUNCH_ALWAYS:
            launchFlags |= Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_DOCUMENT<span class="hljs-comment">;</span>
            <span class="hljs-keyword">break</span><span class="hljs-comment">;</span>
        case ActivityInfo<span class="hljs-preprocessor">.DOCUMENT</span>_LAUNCH_NEVER:
            launchFlags &= ~Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_MULTIPLE_TASK<span class="hljs-comment">;</span>
            <span class="hljs-keyword">break</span><span class="hljs-comment">;</span>
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

这段代码就是处理和FLAG_ACTIVITY_NEW_DOCUMENT相关的,我们知道android中的activity启动标记位既可以通过intent附加,也可以在AndroidManifest中指定,但是如果intent和AndroidManifest中的冲突怎么办呢?这段代码的开始就给出的处理策略:如果冲突就依据AndroidManifest的。如果不冲突的话,那么就获得相应的具体的documentLaunchMode,documentLaunchMode一共有以下4种:
这里写图片描述
这里就对这4种模式进行处理。

<code class="hljs erlang-repl has-numbering"><span class="hljs-function_or_atom">final</span> <span class="hljs-function_or_atom">boolean</span> <span class="hljs-function_or_atom">launchTaskBehind</span> = <span class="hljs-function_or_atom">r</span>.<span class="hljs-function_or_atom">mLaunchTaskBehind</span>
                && <span class="hljs-exclamation_mark">!</span><span class="hljs-function_or_atom">launchSingleTask</span> && <span class="hljs-exclamation_mark">!</span><span class="hljs-function_or_atom">launchSingleInstance</span>
                && (<span class="hljs-function_or_atom">launchFlags</span> & <span class="hljs-variable">Intent</span>.<span class="hljs-variable">FLAG_ACTIVITY_NEW_DOCUMENT</span>) <span class="hljs-exclamation_mark">!</span>= <span class="hljs-number">0</span>;</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>

下面主要就是处理FLAG_ACTIVITY_NEW_TASK时的result值回传问题:

<code class="hljs avrasm has-numbering">if (r<span class="hljs-preprocessor">.resultTo</span> != null && (launchFlags & Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_TASK) != <span class="hljs-number">0</span>
        && r<span class="hljs-preprocessor">.resultTo</span><span class="hljs-preprocessor">.task</span><span class="hljs-preprocessor">.stack</span> != null) {
    // For whatever reason this activity is being launched into a new
    // task...  yet the caller has requested a result back.  Well, that
    // is pretty messed up, so instead immediately send back a cancel
    // <span class="hljs-keyword">and</span> let the new task continue launched as normal without a
    // dependency on its originator.
    Slog<span class="hljs-preprocessor">.w</span>(TAG, <span class="hljs-string">"Activity is launching as a new task, so cancelling activity result."</span>)<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.resultTo</span><span class="hljs-preprocessor">.task</span><span class="hljs-preprocessor">.stack</span><span class="hljs-preprocessor">.sendActivityResultLocked</span>(-<span class="hljs-number">1</span>,
            r<span class="hljs-preprocessor">.resultTo</span>, r<span class="hljs-preprocessor">.resultWho</span>, r<span class="hljs-preprocessor">.requestCode</span>,
            Activity<span class="hljs-preprocessor">.RESULT</span>_CANCELED, null)<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.resultTo</span> = null<span class="hljs-comment">;</span>
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

这里的注释写的很清楚了,就是说在使用了FLAG_ACTIVITY_NEW_TASK的情况下如果使用startActivityForResult方法启动activity的话,那么得到的result将永远是RESULT_CANCELED。这个在intent的api文档中也有说明。

<code class="hljs avrasm has-numbering">// If we are actually going to launch <span class="hljs-keyword">in</span> to a new task, there are some cases where
// we further want to do multiple task.
if ((launchFlags & Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_NEW_TASK) != <span class="hljs-number">0</span>) {
    if (launchTaskBehind
            || r<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.documentLaunchMode</span> == ActivityInfo<span class="hljs-preprocessor">.DOCUMENT</span>_LAUNCH_ALWAYS) {
        launchFlags |= Intent<span class="hljs-preprocessor">.FLAG</span>_ACTIVITY_MULTIPLE_TASK<span class="hljs-comment">;</span>
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>

这段代码是处理FLAG_ACTIVITY_MULTIPLE_TASK的,这个标记通常都会与FLAG_ACTIVITY_NEW_TASK或者FLAG_ACTIVITY_NEW_DOCUMENT一起使用。FLAG_ACTIVITY_MULTIPLE_TASK意思是一个activity可以运行在多个task中,启动的时候直接创建新的task,然后把activity放进去,而不是查找是不是有一个已经存在的task。google不建议app开发者主动使用这个标记。

<code class="hljs cs has-numbering"><span class="hljs-comment">// We'll invoke onUserLeaving before onPause only if the launching</span>
<span class="hljs-comment">// activity did not explicitly state that this is an automated launch.</span>
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == <span class="hljs-number">0</span>;
<span class="hljs-keyword">if</span> (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
        <span class="hljs-string">"startActivity() => mUserLeaving="</span> + mUserLeaving);

<span class="hljs-comment">// If the caller has asked not to resume at this point, we make note</span>
<span class="hljs-comment">// of this in the record so that we can skip it when trying to find</span>
<span class="hljs-comment">// the top running activity.</span>
<span class="hljs-keyword">if</span> (!doResume) {
    r.delayedResume = <span class="hljs-keyword">true</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

这段代码首先处理了FLAG_ACTIVITY_NO_USER_ACTION标记,这个标记表示当前activity的启动不是用户主观要求的,可能是系统某些组件内部逻辑请求的,比如闹钟响起界面,手机电话来电界面等。然后就是如果用户指明了暂时不要resume这个activity的话,我们就把ActivityRecord中的delayedResume置为true,方便后期查找顶端运行的activity。

<code class="hljs fix has-numbering"><span class="hljs-attribute">ActivityRecord notTop </span>=<span class="hljs-string">
                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>

这里是处理FLAG_ACTIVITY_PREVIOUS_IS_TOP的,如果设置了这个标记的话,那么notTop就是r本身,如果没有的话那就是null。FLAG_ACTIVITY_PREVIOUS_IS_TOP的含义是:当前启动的activity不被考虑是task的顶端,而启动它的前一个activity是顶端,这适合于当前activity只是执行一个很短的操作,并且很快就会销毁的情况下。

<code class="hljs sql has-numbering">// If the onlyIfNeeded flag is <span class="hljs-operator"><span class="hljs-keyword">set</span>, <span class="hljs-keyword">then</span> we can <span class="hljs-keyword">do</span> this <span class="hljs-keyword">if</span> the activity
// being launched <span class="hljs-keyword">is</span> the same <span class="hljs-keyword">as</span> the one making the <span class="hljs-keyword">call</span>...  <span class="hljs-keyword">or</span>, <span class="hljs-keyword">as</span>
// a special <span class="hljs-keyword">case</span>, <span class="hljs-keyword">if</span> we <span class="hljs-keyword">do</span> <span class="hljs-keyword">not</span> know the caller <span class="hljs-keyword">then</span> we <span class="hljs-aggregate">count</span> the
// <span class="hljs-keyword">current</span> top activity <span class="hljs-keyword">as</span> the caller.
<span class="hljs-keyword">if</span> ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != <span class="hljs-number">0</span>) {
    ActivityRecord checkedCaller = sourceRecord;</span>
    if (checkedCaller == null) {
        checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
    }
    if (!checkedCaller.realActivity.equals(r.realActivity)) {
        // Caller is not the same as launcher, so always needed.
        startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>

这段代码中的注释说的很清楚,这里如果我们的startFlags中有START_FLAG_ONLY_IF_NEEDED的话,表示只在需要的情况下才会启动目标,即如果被启动的对象和调用者是同一个的时候,那么就没有必要重复操作。

<code class="hljs java has-numbering"><span class="hljs-comment">// If the caller is not coming from another activity, but has given us an</span>
<span class="hljs-comment">// explicit task into which they would like us to launch the new activity,</span>
<span class="hljs-comment">// then let's see about doing that.</span>
<span class="hljs-keyword">if</span> (sourceRecord == <span class="hljs-keyword">null</span> && inTask != <span class="hljs-keyword">null</span> && inTask.stack != <span class="hljs-keyword">null</span>) {
    <span class="hljs-keyword">final</span> Intent baseIntent = inTask.getBaseIntent();
    <span class="hljs-keyword">final</span> ActivityRecord root = inTask.getRootActivity();
    <span class="hljs-keyword">if</span> (baseIntent == <span class="hljs-keyword">null</span>) {
        ActivityOptions.abort(options);
        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Launching into task without base intent: "</span>
                + inTask);
    }

    <span class="hljs-comment">// If this task is empty, then we are adding the first activity -- it</span>
    <span class="hljs-comment">// determines the root, and must be launching as a NEW_TASK.</span>
    <span class="hljs-keyword">if</span> (launchSingleInstance || launchSingleTask) {
        <span class="hljs-keyword">if</span> (!baseIntent.getComponent().equals(r.intent.getComponent())) {
            ActivityOptions.abort(options);
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Trying to launch singleInstance/Task "</span>
                    + r + <span class="hljs-string">" into different task "</span> + inTask);
        }
        <span class="hljs-keyword">if</span> (root != <span class="hljs-keyword">null</span>) {
            ActivityOptions.abort(options);
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Caller with inTask "</span> + inTask
                    + <span class="hljs-string">" has root "</span> + root + <span class="hljs-string">" but target is singleInstance/Task"</span>);
        }
    }

    <span class="hljs-comment">// If task is empty, then adopt the interesting intent launch flags in to the</span>
    <span class="hljs-comment">// activity being started.</span>
    <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> flagsOfInterest = Intent.FLAG_ACTIVITY_NEW_TASK
                | Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
                | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
        launchFlags = (launchFlags&~flagsOfInterest)
                | (baseIntent.getFlags()&flagsOfInterest);
        intent.setFlags(launchFlags);
        inTask.setIntent(r);
        addingToTask = <span class="hljs-keyword">true</span>;

    <span class="hljs-comment">// If the task is not empty and the caller is asking to start it as the root</span>
    <span class="hljs-comment">// of a new task, then we don't actually want to start this on the task.  We</span>
    <span class="hljs-comment">// will bring the task to the front, and possibly give it a new intent.</span>
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != <span class="hljs-number">0</span>) {
        addingToTask = <span class="hljs-keyword">false</span>;

    } <span class="hljs-keyword">else</span> {
        addingToTask = <span class="hljs-keyword">true</span>;
    }

    reuseTask = inTask;
} <span class="hljs-keyword">else</span> {
    inTask = <span class="hljs-keyword">null</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li></ul>

这里需要注意一下inTask这个方法参数,这个参数和android 5.0中的最近任务栏有关。android 5.0中引入了重启后恢复Task的功能,当用户从最近任务栏中启动“恢复的task”的时候,inTask是不为空的,但是这时候的sourceRecord是空的,这段代码就是处理从最近任务中启动一个activity的过程。首先判断的是查看inTask中的用于启动root activity的intent是不是为空,如果为空的话那就抛出IllegalArgumentException异常终止运行,因为没有root activity的intent整个task就不能构建了。接下来就是看当前activity的启动模式是不是single instance或者single task,如果是的话,并且是从一个不同的task中启动的话,那就抛出IllegalArgumentException,因为这两种启动模式都不能在别的task中运行。同时如果root activity不为空,那也会抛出IllegalArgumentException,因为singleInstance/Task启动的时候task中已经有root activity了。接下来如果root activity是空的话,就采用上面baseIntent中的标记位来启动目标activity,这些标记位上最近用户使用时候的标记位。
下面我们继续分析代码:

<code class="hljs coffeescript has-numbering"><span class="hljs-keyword">if</span> (inTask == <span class="hljs-literal">null</span>) {
    <span class="hljs-keyword">if</span> (sourceRecord == <span class="hljs-literal">null</span>) {
        <span class="hljs-regexp">//</span> This activity <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> being started from another...  <span class="hljs-keyword">in</span> <span class="hljs-keyword">this</span>
        <span class="hljs-regexp">//</span> <span class="hljs-reserved">case</span> we -always- start a <span class="hljs-keyword">new</span> task.
        <span class="hljs-keyword">if</span> ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == <span class="hljs-number">0</span> && inTask == <span class="hljs-literal">null</span>) {
            Slog.w(TAG, <span class="hljs-string">"startActivity called from non-Activity context; forcing "</span> +
                    <span class="hljs-string">"Intent.FLAG_ACTIVITY_NEW_TASK for: "</span> + intent);
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
        }
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
        <span class="hljs-regexp">//</span> The original activity who <span class="hljs-keyword">is</span> starting us <span class="hljs-keyword">is</span> running as a single
        <span class="hljs-regexp">//</span> instance...  <span class="hljs-keyword">this</span> <span class="hljs-keyword">new</span> activity it <span class="hljs-keyword">is</span> starting must go <span class="hljs-literal">on</span> its
        <span class="hljs-regexp">//</span> own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (launchSingleInstance || launchSingleTask) {
        <span class="hljs-regexp">//</span> The activity being started <span class="hljs-keyword">is</span> a single instance...  it always
        <span class="hljs-regexp">//</span> gets launched into its own task.
        launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>

这段代码是关于FLAG_ACTIVITY_NEW_TASK标记的处理,逻辑比较简单,就不赘述了。
接下来的代码是一个安全检查:

<code class="hljs bash has-numbering">ActivityInfo newTaskInfo = null;
Intent newTaskIntent = null;
ActivityStack <span class="hljs-built_in">source</span>Stack;
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">source</span>Record != null) {
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">source</span>Record.finishing) {
        // If the <span class="hljs-built_in">source</span> is finishing, we can<span class="hljs-string">'t further count it as our source.  This
        // is because the task it is associated with may now be empty and on its way out,
        // so we don'</span>t want to blindly throw it <span class="hljs-keyword">in</span> to that task.  Instead we will take
        // the NEW_TASK flow and try to find a task <span class="hljs-keyword">for</span> it. But save the task information
        // so it can be used when creating the new task.
        <span class="hljs-keyword">if</span> ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == <span class="hljs-number">0</span>) {
            Slog.w(TAG, <span class="hljs-string">"startActivity called from finishing "</span> + <span class="hljs-built_in">source</span>Record
                    + <span class="hljs-string">"; forcing "</span> + <span class="hljs-string">"Intent.FLAG_ACTIVITY_NEW_TASK for: "</span> + intent);
            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
            newTaskInfo = <span class="hljs-built_in">source</span>Record.info;
            newTaskIntent = <span class="hljs-built_in">source</span>Record.task.intent;
        }
        <span class="hljs-built_in">source</span>Record = null;
        <span class="hljs-built_in">source</span>Stack = null;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-built_in">source</span>Stack = <span class="hljs-built_in">source</span>Record.task.stack;
    }
} <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">source</span>Stack = null;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li></ul>

主要是检查启动它的activity是不是快要被销毁了,如果是的话那就需要启动一个新的task,从而将这个activity放到这个task中去。
下面的代码就是task查找和定位的过程:

<code class="hljs coffeescript has-numbering"><span class="hljs-regexp">//</span> We may want to <span class="hljs-keyword">try</span> to place the <span class="hljs-keyword">new</span> activity <span class="hljs-keyword">in</span> to an existing task.  We always
<span class="hljs-regexp">//</span> <span class="hljs-keyword">do</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> the target activity <span class="hljs-keyword">is</span> singleTask <span class="hljs-keyword">or</span> singleInstance; we will also <span class="hljs-keyword">do</span>
<span class="hljs-regexp">//</span> <span class="hljs-keyword">this</span> <span class="hljs-keyword">if</span> NEW_TASK has been requested, <span class="hljs-keyword">and</span> there <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> an additional qualifier telling
<span class="hljs-regexp">//</span> us to still place it <span class="hljs-keyword">in</span> a <span class="hljs-keyword">new</span> <span class="hljs-attribute">task</span>: multi task, always doc mode, <span class="hljs-keyword">or</span> being asked to
<span class="hljs-regexp">//</span> launch <span class="hljs-keyword">this</span> as a <span class="hljs-keyword">new</span> task behind the current one.
<span class="hljs-keyword">if</span> (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != <span class="hljs-number">0</span> &&
        (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == <span class="hljs-number">0</span>)
        || launchSingleInstance || launchSingleTask) {
    <span class="hljs-regexp">//</span> If bring to front <span class="hljs-keyword">is</span> requested, <span class="hljs-keyword">and</span> <span class="hljs-literal">no</span> result <span class="hljs-keyword">is</span> requested <span class="hljs-keyword">and</span> we have <span class="hljs-keyword">not</span>
    <span class="hljs-regexp">//</span> been given an explicit task to launch <span class="hljs-keyword">in</span> to, <span class="hljs-keyword">and</span>
    <span class="hljs-regexp">//</span> we can find a task that was started <span class="hljs-reserved">with</span> <span class="hljs-keyword">this</span> same
    <span class="hljs-regexp">//</span> component, <span class="hljs-keyword">then</span> instead <span class="hljs-keyword">of</span> launching bring that one to the front.
    <span class="hljs-keyword">if</span> (inTask == <span class="hljs-literal">null</span> && r.resultTo == <span class="hljs-literal">null</span>) {
        <span class="hljs-regexp">//</span> See <span class="hljs-keyword">if</span> there <span class="hljs-keyword">is</span> a task to bring to the front.  If <span class="hljs-keyword">this</span> <span class="hljs-keyword">is</span>
        <span class="hljs-regexp">//</span> a SINGLE_INSTANCE activity, there can be one <span class="hljs-keyword">and</span> only one
        <span class="hljs-regexp">//</span> instance <span class="hljs-keyword">of</span> it <span class="hljs-keyword">in</span> the history, <span class="hljs-keyword">and</span> it <span class="hljs-keyword">is</span> always <span class="hljs-keyword">in</span> its own
        <span class="hljs-regexp">//</span> unique task, so we <span class="hljs-keyword">do</span> a special search.
        ActivityRecord intentActivity = !launchSingleInstance ?
                findTaskLocked(r) : findActivityLocked(intent, r.info);
        <span class="hljs-keyword">if</span> (intentActivity != <span class="hljs-literal">null</span>) {
            <span class="hljs-regexp">//</span> When the flags NEW_TASK <span class="hljs-keyword">and</span> CLEAR_TASK are set, <span class="hljs-keyword">then</span> the task gets reused
            <span class="hljs-regexp">//</span> but still needs to be a lock task mode violation since the task gets
            <span class="hljs-regexp">//</span> cleared out <span class="hljs-keyword">and</span> the device would otherwise leave the locked task.
            <span class="hljs-keyword">if</span> (isLockTaskModeViolation(intentActivity.task,
                    (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
                showLockTaskToast();
                Slog.e(TAG, <span class="hljs-string">"startActivityUnchecked: Attempt to violate Lock Task Mode"</span>);
                <span class="hljs-keyword">return</span> ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
            }
            <span class="hljs-keyword">if</span> (r.task == <span class="hljs-literal">null</span>) {
                r.task = intentActivity.task;
            }
            <span class="hljs-keyword">if</span> (intentActivity.task.intent == <span class="hljs-literal">null</span>) {
                <span class="hljs-regexp">//</span> This task was started because <span class="hljs-keyword">of</span> movement <span class="hljs-keyword">of</span>
                <span class="hljs-regexp">//</span> the activity based <span class="hljs-literal">on</span> affinity...  now that we
                <span class="hljs-regexp">//</span> are actually launching it, we can assign the
                <span class="hljs-regexp">//</span> base intent.
                intentActivity.task.setIntent(r);
            }
            targetStack = intentActivity.task.stack;
            targetStack.mLastPausedActivity = <span class="hljs-literal">null</span>;
            <span class="hljs-regexp">//</span> If the target task <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> the front, <span class="hljs-keyword">then</span> we need
            <span class="hljs-regexp">//</span> to bring it to the front...  except...  well, <span class="hljs-reserved">with</span>
            <span class="hljs-regexp">//</span> SINGLE_TASK_LAUNCH it<span class="hljs-string">'s not entirely clear.  We'</span>d like
            <span class="hljs-regexp">//</span> to have the same behavior as <span class="hljs-keyword">if</span> a <span class="hljs-keyword">new</span> instance was
            <span class="hljs-regexp">//</span> being started, which means <span class="hljs-keyword">not</span> bringing it to the front
            <span class="hljs-regexp">//</span> <span class="hljs-keyword">if</span> the caller <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> itself <span class="hljs-keyword">in</span> the front.
            final ActivityStack focusStack = getFocusedStack();
            ActivityRecord curTop = (focusStack == <span class="hljs-literal">null</span>)
                    ? <span class="hljs-literal">null</span> : focusStack.topRunningNonDelayedActivityLocked(notTop);
            boolean movedToFront = <span class="hljs-literal">false</span>;
            <span class="hljs-keyword">if</span> (curTop != <span class="hljs-literal">null</span> && (curTop.task != intentActivity.task ||
                    curTop.task != focusStack.topTask())) {
                r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
                <span class="hljs-keyword">if</span> (sourceRecord == <span class="hljs-literal">null</span> || (sourceStack.topActivity() != <span class="hljs-literal">null</span> &&
                        sourceStack.topActivity().task == sourceRecord.task)) {
                    <span class="hljs-regexp">//</span> We really <span class="hljs-keyword">do</span> want to push <span class="hljs-keyword">this</span> one into the user<span class="hljs-string">'s face, right now.
                    if (launchTaskBehind && sourceRecord != null) {
                        intentActivity.setTaskToAffiliateWith(sourceRecord.task);
                    }
                    movedHome = true;
                    targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
                            options, r.appTimeTracker, "bringingFoundTaskToFront");
                    movedToFront = true;
                    if ((launchFlags &
                            (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
                        // Caller wants to appear on home activity.
                        intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
                    }
                    options = null;
                }
            }
            if (!movedToFront) {
                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
                        + " from " + intentActivity);
                targetStack.moveToFront("intentActivityFound");
            }

            // If the caller has requested that the target task be
            // reset, then do so.
            if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
                intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
            }
            if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
                // We don'</span>t need to start a <span class="hljs-keyword">new</span> activity, <span class="hljs-keyword">and</span>
                <span class="hljs-regexp">//</span> the client said <span class="hljs-keyword">not</span> to <span class="hljs-keyword">do</span> anything <span class="hljs-keyword">if</span> that
                <span class="hljs-regexp">//</span> <span class="hljs-keyword">is</span> the <span class="hljs-reserved">case</span>, so <span class="hljs-keyword">this</span> <span class="hljs-keyword">is</span> it!  And <span class="hljs-keyword">for</span> paranoia, make
                <span class="hljs-regexp">//</span> sure we have correctly resumed the top activity.
                <span class="hljs-keyword">if</span> (doResume) {
                    resumeTopActivitiesLocked(targetStack, <span class="hljs-literal">null</span>, options);

                    <span class="hljs-regexp">//</span> Make sure to notify Keyguard as well <span class="hljs-keyword">if</span> we are <span class="hljs-keyword">not</span> running an app
                    <span class="hljs-regexp">//</span> transition later.
                    <span class="hljs-keyword">if</span> (!movedToFront) {
                        notifyActivityDrawnForKeyguard();
                    }
                } <span class="hljs-keyword">else</span> {
                    ActivityOptions.abort(options);
                }
                <span class="hljs-keyword">return</span> ActivityManager.START_RETURN_INTENT_TO_CALLER;
            }
            <span class="hljs-keyword">if</span> ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
                <span class="hljs-regexp">//</span> The caller has requested to completely replace any
                <span class="hljs-regexp">//</span> existing task <span class="hljs-reserved">with</span> its <span class="hljs-keyword">new</span> activity.  Well that should
                <span class="hljs-regexp">//</span> <span class="hljs-keyword">not</span> be too hard...
                reuseTask = intentActivity.task;
                reuseTask.performClearTaskLocked();
                reuseTask.setIntent(r);
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != <span class="hljs-number">0</span>
                    || launchSingleInstance || launchSingleTask) {
                <span class="hljs-regexp">//</span> In <span class="hljs-keyword">this</span> situation we want to remove all activities
                <span class="hljs-regexp">//</span> from the task up to the one being started.  In most
                <span class="hljs-regexp">//</span> cases <span class="hljs-keyword">this</span> means we are resetting the task to its
                <span class="hljs-regexp">//</span> initial state.
                ActivityRecord top =
                        intentActivity.task.performClearTaskLocked(r, launchFlags);
                <span class="hljs-keyword">if</span> (top != <span class="hljs-literal">null</span>) {
                    <span class="hljs-keyword">if</span> (top.frontOfTask) {
                        <span class="hljs-regexp">//</span> Activity aliases may mean we use different
                        <span class="hljs-regexp">//</span> intents <span class="hljs-keyword">for</span> the top activity, so make sure
                        <span class="hljs-regexp">//</span> the task now has the identity <span class="hljs-keyword">of</span> the <span class="hljs-keyword">new</span>
                        <span class="hljs-regexp">//</span> intent.
                        top.task.setIntent(r);
                    }
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                            r, top.task);
                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
                } <span class="hljs-keyword">else</span> {
                    <span class="hljs-regexp">//</span> A special <span class="hljs-attribute">case</span>: we need to start the activity because it <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span>
                    <span class="hljs-regexp">//</span> currently running, <span class="hljs-keyword">and</span> the caller has asked to clear the current
                    <span class="hljs-regexp">//</span> task to have <span class="hljs-keyword">this</span> activity at the top.
                    addingToTask = <span class="hljs-literal">true</span>;
                    <span class="hljs-regexp">//</span> Now pretend like <span class="hljs-keyword">this</span> activity <span class="hljs-keyword">is</span> being started <span class="hljs-keyword">by</span> the top <span class="hljs-keyword">of</span> its
                    <span class="hljs-regexp">//</span> task, so it <span class="hljs-keyword">is</span> put <span class="hljs-keyword">in</span> the right place.
                    sourceRecord = intentActivity;
                    TaskRecord task = sourceRecord.task;
                    <span class="hljs-keyword">if</span> (task != <span class="hljs-literal">null</span> && task.stack == <span class="hljs-literal">null</span>) {
                        <span class="hljs-regexp">//</span> Target stack got cleared <span class="hljs-keyword">when</span> we all activities were removed
                        <span class="hljs-regexp">//</span> above. Go ahead <span class="hljs-keyword">and</span> reset it.
                        targetStack = computeStackFocus(sourceRecord, <span class="hljs-literal">false</span> <span class="hljs-regexp">/* newTask */</span>);
                        targetStack.addTask(
                                task, !launchTaskBehind <span class="hljs-regexp">/* toTop */</span>, <span class="hljs-literal">false</span> <span class="hljs-regexp">/* moving */</span>);
                    }

                }
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (r.realActivity.equals(intentActivity.task.realActivity)) {
                <span class="hljs-regexp">//</span> In <span class="hljs-keyword">this</span> <span class="hljs-reserved">case</span> the top activity <span class="hljs-literal">on</span> the task <span class="hljs-keyword">is</span> the
                <span class="hljs-regexp">//</span> same as the one being launched, so we take that
                <span class="hljs-regexp">//</span> as a request to bring the task to the foreground.
                <span class="hljs-regexp">//</span> If the top activity <span class="hljs-keyword">in</span> the task <span class="hljs-keyword">is</span> the root
                <span class="hljs-regexp">//</span> activity, deliver <span class="hljs-keyword">this</span> <span class="hljs-keyword">new</span> intent to it <span class="hljs-keyword">if</span> it
                <span class="hljs-regexp">//</span> desires.
                <span class="hljs-keyword">if</span> (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != <span class="hljs-number">0</span> || launchSingleTop)
                        && intentActivity.realActivity.equals(r.realActivity)) {
                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                            intentActivity.task);
                    <span class="hljs-keyword">if</span> (intentActivity.frontOfTask) {
                        intentActivity.task.setIntent(r);
                    }
                    intentActivity.deliverNewIntentLocked(callingUid, r.intent,
                            r.launchedFromPackage);
                } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!r.intent.filterEquals(intentActivity.task.intent)) {
                    <span class="hljs-regexp">//</span> In <span class="hljs-keyword">this</span> <span class="hljs-reserved">case</span> we are launching the root activity
                    <span class="hljs-regexp">//</span> <span class="hljs-keyword">of</span> the task, but <span class="hljs-reserved">with</span> a different intent.  We
                    <span class="hljs-regexp">//</span> should start a <span class="hljs-keyword">new</span> instance <span class="hljs-literal">on</span> top.
                    addingToTask = <span class="hljs-literal">true</span>;
                    sourceRecord = intentActivity;
                }
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == <span class="hljs-number">0</span>) {
                <span class="hljs-regexp">//</span> In <span class="hljs-keyword">this</span> <span class="hljs-reserved">case</span> an activity <span class="hljs-keyword">is</span> being launched <span class="hljs-keyword">in</span> to an
                <span class="hljs-regexp">//</span> existing task, without resetting that task.  This
                <span class="hljs-regexp">//</span> <span class="hljs-keyword">is</span> typically the situation <span class="hljs-keyword">of</span> launching an activity
                <span class="hljs-regexp">//</span> from a notification <span class="hljs-keyword">or</span> shortcut.  We want to place
                <span class="hljs-regexp">//</span> the <span class="hljs-keyword">new</span> activity <span class="hljs-literal">on</span> top <span class="hljs-keyword">of</span> the current task.
                addingToTask = <span class="hljs-literal">true</span>;
                sourceRecord = intentActivity;
            } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (!intentActivity.task.rootWasReset) {
                <span class="hljs-regexp">//</span> In <span class="hljs-keyword">this</span> <span class="hljs-reserved">case</span> we are launching <span class="hljs-keyword">in</span> to an existing task
                <span class="hljs-regexp">//</span> that has <span class="hljs-keyword">not</span> yet been started from its front door.
                <span class="hljs-regexp">//</span> The current task has been brought to the front.
                <span class="hljs-regexp">//</span> Ideally, we<span class="hljs-string">'d probably like to place this new task
                // at the bottom of its stack, but that'</span>s a little hard
                <span class="hljs-regexp">//</span> to <span class="hljs-keyword">do</span> <span class="hljs-reserved">with</span> the current organization <span class="hljs-keyword">of</span> the code so
                <span class="hljs-regexp">//</span> <span class="hljs-keyword">for</span> now we<span class="hljs-string">'ll just drop it.
                intentActivity.task.setIntent(r);
            }
            if (!addingToTask && reuseTask == null) {
                // We didn'</span>t <span class="hljs-keyword">do</span> anything...  but it was needed (a.k.a., client
                <span class="hljs-regexp">//</span> don<span class="hljs-string">'t use that intent!)  And for paranoia, make
                // sure we have correctly resumed the top activity.
                if (doResume) {
                    targetStack.resumeTopActivityLocked(null, options);
                    if (!movedToFront) {
                        // Make sure to notify Keyguard as well if we are not running an app
                        // transition later.
                        notifyActivityDrawnForKeyguard();
                    }
                } else {
                    ActivityOptions.abort(options);
                }
                return ActivityManager.START_TASK_TO_FRONT;
            }
        }
    }
}</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li><li>151</li><li>152</li><li>153</li><li>154</li><li>155</li><li>156</li><li>157</li><li>158</li><li>159</li><li>160</li><li>161</li><li>162</li><li>163</li><li>164</li><li>165</li><li>166</li><li>167</li><li>168</li><li>169</li><li>170</li><li>171</li><li>172</li><li>173</li><li>174</li><li>175</li><li>176</li><li>177</li><li>178</li><li>179</li><li>180</li><li>181</li><li>182</li><li>183</li><li>184</li><li>185</li><li>186</li><li>187</li><li>188</li><li>189</li><li>190</li><li>191</li><li>192</li><li>193</li><li>194</li><li>195</li><li>196</li><li>197</li><li>198</li><li>199</li><li>200</li><li>201</li><li>202</li><li>203</li><li>204</li><li>205</li><li>206</li><li>207</li><li>208</li></ul>

这部分的代码就是在查找合适的已经存在的task,然后把activity放进去,如果可以的话,那就将这个activity resume。接下来的代码主要就是基于newTask是false的情况,不过也是有例外的,比如代码中设置了NEW_TASK的标记,但是经过后面的判断之后addingToTask为false,此时newTask还是为真。这里我们就不贴出代码了,大家可以自行查看,这部分的代码没有复杂的逻辑,都只是一些状态,标记的判断和处理。
我们的startActivityUncheckedLocked方法就是最后是通过ActivityStack的startActivityLocked方法实际启动了一个activity。这个方法不仅是AMS启动activity的关键,同时也是Activity后续能否再WMS中得到正常处理的关键。
startActivityLocked是启动activity的最后一站,现在我们梳理一下它的工作。
1). 首先,如果目标activity不是在新的task中启动的,也就是newTask为false的情况下,那么程序要找到目标activity位于那个老的task中,这个需要遍历mTaskHistory才能找到。找到后,如果这个task当前对用户是不可见的,那么只需要将它放到历史记录中,并且再WMS中做好注册,但是不要启动它。
2). 将这个activity放到task的最顶层,这样用户才能和它交互,代码如下:

<code class="hljs avrasm has-numbering">// Slot the activity into the history stack <span class="hljs-keyword">and</span> proceed
if (DEBUG_ADD_REMOVE) Slog<span class="hljs-preprocessor">.i</span>(TAG, <span class="hljs-string">"Adding activity "</span> + r + <span class="hljs-string">" to stack to task "</span> + task,
        new RuntimeException(<span class="hljs-string">"here"</span>)<span class="hljs-preprocessor">.fillInStackTrace</span>())<span class="hljs-comment">;</span>
task<span class="hljs-preprocessor">.addActivityToTop</span>(r)<span class="hljs-comment">;</span>
task<span class="hljs-preprocessor">.setFrontOfTask</span>()<span class="hljs-comment">;</span>

r<span class="hljs-preprocessor">.putInHistory</span>()<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

3). 接下来,如果不是AMS中的第一个activity的话(numActivities() > 0),则执行切换动画,不过这也是取决于FLAG_ACTIVITY_NO_ANIMATION标记的。执行的动画类型分为两种:TRANSIT_TASK_OPEN表示启动新的task和TRANSIT_ACTIVITY_OPEN表示不启动新的task。
4). 一个activity的UI界面要想再终端屏幕上显示出来,很重要的一点就是他必须向WMS中添加token,以便于WMS在启动窗口的时候能够找到它。代码如下:

<code class="hljs avrasm has-numbering">mWindowManager<span class="hljs-preprocessor">.addAppToken</span>(task<span class="hljs-preprocessor">.mActivities</span><span class="hljs-preprocessor">.indexOf</span>(r),
                    r<span class="hljs-preprocessor">.appToken</span>, r<span class="hljs-preprocessor">.task</span><span class="hljs-preprocessor">.taskId</span>, mStackId, r<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.screenOrientation</span>, r<span class="hljs-preprocessor">.fullscreen</span>,
                    (r<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.flags</span> & ActivityInfo<span class="hljs-preprocessor">.FLAG</span>_SHOW_FOR_ALL_USERS) != <span class="hljs-number">0</span>, r<span class="hljs-preprocessor">.userId</span>,
                    r<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.configChanges</span>, task<span class="hljs-preprocessor">.voiceSession</span> != null, r<span class="hljs-preprocessor">.mLaunchTaskBehind</span>)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

5). 每一个activity可能在AndroidManifest中会指定affinity,这个属性就是指定了它想要运行的task的名称。因而如果启动了一个新的task,就需要检查是否存在对这个task同affinity的其他activity。另外,如果用户使用了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记的话,就满足了need需要了,此时需要调用resetTaskIfNeededLocked方法,保证task中目前这个activity是root。操作的代码如下:

<code class="hljs cs has-numbering"><span class="hljs-keyword">if</span> (newTask) {
    <span class="hljs-comment">// Even though this activity is starting fresh, we still need</span>
    <span class="hljs-comment">// to reset it to make sure we apply affinities to move any</span>
    <span class="hljs-comment">// existing activities from other tasks in to it.</span>
    <span class="hljs-comment">// If the caller has requested that the target task be</span>
    <span class="hljs-comment">// reset, then do so.</span>
    <span class="hljs-keyword">if</span> ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != <span class="hljs-number">0</span>) {
        resetTaskIfNeededLocked(r, r);
        doShow = topRunningNonDelayedActivityLocked(<span class="hljs-keyword">null</span>) == r;
    }
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (options != <span class="hljs-keyword">null</span> && <span class="hljs-keyword">new</span> ActivityOptions(options).getAnimationType()
        == ActivityOptions.ANIM_SCENE_TRANSITION) {
    doShow = <span class="hljs-keyword">false</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>

6). 最后调用resumeTopActivitiesLocked来恢复最上层的activity,并且pause之前的activity;这是一方面,另一方面,在activity切换的过程中还要展示切换动画,然后两个新旧activity还会向WMS分别申请和释放surface,最终完成老的activity不显示,新的activity显示的任务。
resumeTopActivitiesLocked是AMS中很多地方都会调用到的方法,主要作用是将位于栈顶的activity显示出来,这时,当前的activity(就是mResumedActivity指向的那个activity)还显示在前端。这里的操作就要将这个activity pause掉放到后端。下面我们看一下resumeTopActivitiesLocked方法的处理逻辑。
resumeTopActivitiesLocked@ActivityStackSupervisor.java

<code class="hljs java has-numbering"><span class="hljs-keyword">boolean</span> resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    <span class="hljs-comment">// 如果目标stack为空的话,那么就将目标栈赋值为mFocusedStack,这是正在前端和用户交互的栈</span>
    <span class="hljs-keyword">if</span> (targetStack == <span class="hljs-keyword">null</span>) {
        targetStack = mFocusedStack;
    }
    <span class="hljs-comment">// Do targetStack first.</span>
    <span class="hljs-keyword">boolean</span> result = <span class="hljs-keyword">false</span>;
    <span class="hljs-comment">// 如果目标stack是前端stack,那么就resume这个栈顶的activity</span>
    <span class="hljs-keyword">if</span> (isFrontStack(targetStack)) {
        result = targetStack.resumeTopActivityLocked(target, targetOptions);
    }

    <span class="hljs-comment">// resume各个display上前端栈栈顶的activity</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> displayNdx = mActivityDisplays.size() - <span class="hljs-number">1</span>; displayNdx >= <span class="hljs-number">0</span>; --displayNdx) {
        <span class="hljs-keyword">final</span> ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> stackNdx = stacks.size() - <span class="hljs-number">1</span>; stackNdx >= <span class="hljs-number">0</span>; --stackNdx) {
            <span class="hljs-keyword">final</span> ActivityStack stack = stacks.get(stackNdx);
            <span class="hljs-keyword">if</span> (stack == targetStack) {
                <span class="hljs-comment">// Already started above.</span>
                <span class="hljs-keyword">continue</span>;
            }
            <span class="hljs-keyword">if</span> (isFrontStack(stack)) {
                stack.resumeTopActivityLocked(<span class="hljs-keyword">null</span>);
            }
        }
    }
    <span class="hljs-keyword">return</span> result;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul>

我们看到这个方法最终还是调用ActivityStack的resumeTopActivityLocked来显示activity:
resumeTopActivityLocked@ActivityStack.java

<code class="hljs java has-numbering"><span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    <span class="hljs-comment">// 如果当前正在resume顶端activity的话,那就直接返回false</span>
    <span class="hljs-keyword">if</span> (mStackSupervisor.inResumeTopActivity) {
        <span class="hljs-comment">// Don't even start recursing.</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
    }

    <span class="hljs-keyword">boolean</span> result = <span class="hljs-keyword">false</span>;
    <span class="hljs-keyword">try</span> {
        <span class="hljs-comment">// Protect against recursion.</span>
        mStackSupervisor.inResumeTopActivity = <span class="hljs-keyword">true</span>;
        <span class="hljs-keyword">if</span> (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) {
            mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN;
            mService.updateSleepIfNeededLocked();
        }
        <span class="hljs-comment">// 进一步调用以显示activity</span>
        result = resumeTopActivityInnerLocked(prev, options);
    } <span class="hljs-keyword">finally</span> {
        mStackSupervisor.inResumeTopActivity = <span class="hljs-keyword">false</span>;
    }
    <span class="hljs-keyword">return</span> result;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

上面的代码还是最后调用了resumeTopActivityInnerLocked这个方法来resume activity,下面我们开始分析一下resumeTopActivityInnerLocked这个方法,这个方法比较长,这里我们分段分析。
resumeTopActivityInnerLocked@ActivityStack.java

<code class="hljs coffeescript has-numbering"><span class="hljs-keyword">if</span> (!mService.mBooting && !mService.mBooted) {
    <span class="hljs-regexp">//</span> Not ready yet!
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}

ActivityRecord parent = mActivityContainer.mParentActivity;
<span class="hljs-keyword">if</span> ((parent != <span class="hljs-literal">null</span> && parent.state != ActivityState.RESUMED) ||
        !mActivityContainer.isAttachedLocked()) {
    <span class="hljs-regexp">//</span> Do <span class="hljs-keyword">not</span> resume <span class="hljs-keyword">this</span> stack <span class="hljs-keyword">if</span> its parent <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> resumed.
    <span class="hljs-regexp">//</span> <span class="hljs-attribute">TODO</span>: If <span class="hljs-keyword">in</span> a <span class="hljs-keyword">loop</span>, make sure that parent stack resumeTopActivity <span class="hljs-keyword">is</span> called <span class="hljs-number">1</span>st.
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>

这里的操作还是比较简单的,首先查看系统是否启动完成了,否则就直接返回。如果启动当前activity的activity本身的状态不是RESUMED的话,那么不能启动activity,直接返回false。

<code class="hljs java has-numbering"><span class="hljs-comment">// Find the first activity that is not finishing.</span>
<span class="hljs-comment">// next就是我们需要启动的activity</span>
<span class="hljs-keyword">final</span> ActivityRecord next = topRunningActivityLocked(<span class="hljs-keyword">null</span>);

<span class="hljs-comment">// Remember how we'll process this pause/resume situation, and ensure</span>
<span class="hljs-comment">// that the state is reset however we wind up proceeding.</span>
<span class="hljs-keyword">final</span> <span class="hljs-keyword">boolean</span> userLeaving = mStackSupervisor.mUserLeaving;
mStackSupervisor.mUserLeaving = <span class="hljs-keyword">false</span>;

<span class="hljs-keyword">final</span> TaskRecord prevTask = prev != <span class="hljs-keyword">null</span> ? prev.task : <span class="hljs-keyword">null</span>;
<span class="hljs-keyword">if</span> (next == <span class="hljs-keyword">null</span>) {
    <span class="hljs-comment">// There are no more activities!</span>
    <span class="hljs-comment">// 当前task没有activity,则查找下一个可以显示的task</span>
    <span class="hljs-keyword">final</span> String reason = <span class="hljs-string">"noMoreActivities"</span>;
    <span class="hljs-keyword">if</span> (!mFullscreen) {
        <span class="hljs-comment">// Try to move focus to the next visible stack with a running activity if this</span>
        <span class="hljs-comment">// stack is not covering the entire screen.</span>
        <span class="hljs-keyword">final</span> ActivityStack stack = getNextVisibleStackLocked();
        <span class="hljs-keyword">if</span> (adjustFocusToNextVisibleStackLocked(stack, reason)) {
            <span class="hljs-keyword">return</span> mStackSupervisor.resumeTopActivitiesLocked(stack, prev, <span class="hljs-keyword">null</span>);
        }
    }
    <span class="hljs-comment">// Let's just start up the Launcher...</span>
    <span class="hljs-comment">// 否则就显示home桌面</span>
    ActivityOptions.abort(options);
    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES,
            <span class="hljs-string">"resumeTopActivityLocked: No more activities go home"</span>);
    <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    <span class="hljs-comment">// Only resume home if on home display</span>
    <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> returnTaskType = prevTask == <span class="hljs-keyword">null</span> || !prevTask.isOverHomeStack() ?
            HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
    <span class="hljs-keyword">return</span> isOnHomeDisplay() &&
            mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>

上面的代码就是在正式启动之前的检查,我们继续看接下来的代码:

<code class="hljs lua has-numbering">// If the top activity is the resumed one, nothing to <span class="hljs-keyword">do</span>.
<span class="hljs-keyword">if</span> (mResumedActivity == <span class="hljs-built_in">next</span> && <span class="hljs-built_in">next</span>.state == ActivityState.RESUMED &&
            mStackSupervisor.allResumedActivitiesComplete()) {
    // Make sure we have executed any pending transitions, since there
    // should be nothing left to <span class="hljs-keyword">do</span> at this point.
    mWindowManager.executeAppTransition();
    mNoAnimActivities.clear();
    ActivityOptions.abort(options);
    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES,
            <span class="hljs-string">"resumeTopActivityLocked: Top activity resumed "</span> + <span class="hljs-built_in">next</span>);
    <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

上面的代码会检测,如果我们要启动的activity现在就是在前台的话,那么我们就不用启动了,直接返回false。

<code class="hljs coffeescript has-numbering"><span class="hljs-regexp">//</span> If we are sleeping, <span class="hljs-keyword">and</span> there <span class="hljs-keyword">is</span> <span class="hljs-literal">no</span> resumed activity, <span class="hljs-keyword">and</span> the top
<span class="hljs-regexp">//</span> activity <span class="hljs-keyword">is</span> paused, well that <span class="hljs-keyword">is</span> the state we want.
<span class="hljs-keyword">if</span> (mService.isSleepingOrShuttingDown()
        && mLastPausedActivity == next
        && mStackSupervisor.allPausedActivitiesComplete()) {
    <span class="hljs-regexp">//</span> Make sure we have executed any pending transitions, since there
    <span class="hljs-regexp">//</span> should be nothing left to <span class="hljs-keyword">do</span> at <span class="hljs-keyword">this</span> point.
    mWindowManager.executeAppTransition();
    mNoAnimActivities.clear();
    ActivityOptions.abort(options);
    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES,
            <span class="hljs-string">"resumeTopActivityLocked: Going to sleep and all paused"</span>);
    <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li></ul>

这里会检测,如果系统当前准备休眠或者关机,如果是的话,那么就放弃本次启动。

<code class="hljs lua has-numbering">// The activity may be waiting <span class="hljs-keyword">for</span> stop, but that is no longer
// appropriate <span class="hljs-keyword">for</span> it.
mStackSupervisor.mStoppingActivities.remove(<span class="hljs-built_in">next</span>);
mStackSupervisor.mGoingToSleepActivities.remove(<span class="hljs-built_in">next</span>);
<span class="hljs-built_in">next</span>.sleeping = <span class="hljs-keyword">false</span>;
mStackSupervisor.mWaitingVisibleActivities.remove(<span class="hljs-built_in">next</span>);</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

这里的注释也解释了,如果当前启动的activity正在等待stop,那么就放弃stop直接启动。因为现在已经没有必要将它stop了。

<code class="hljs cs has-numbering"><span class="hljs-comment">// If we are currently pausing an activity, then don't do anything</span>
<span class="hljs-comment">// until that is done.</span>
<span class="hljs-keyword">if</span> (!mStackSupervisor.allPausedActivitiesComplete()) {
   <span class="hljs-keyword">if</span> (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
           <span class="hljs-string">"resumeTopActivityLocked: Skip resume: some activity pausing."</span>);
   <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
   <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>

如果我们当前正在pause一个activity,那么我们需要等到我们的pause动作完成了才能开始启动activity。

<code class="hljs java has-numbering"><span class="hljs-comment">// We need to start pausing the current activity so the top one</span>
<span class="hljs-comment">// can be resumed...</span>
<span class="hljs-keyword">boolean</span> dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != <span class="hljs-number">0</span>;
<span class="hljs-keyword">boolean</span> pausing = mStackSupervisor.pauseBackStacks(userLeaving, <span class="hljs-keyword">true</span>, dontWaitForPause);
<span class="hljs-keyword">if</span> (mResumedActivity != <span class="hljs-keyword">null</span>) {
    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES,
            <span class="hljs-string">"resumeTopActivityLocked: Pausing "</span> + mResumedActivity);
    pausing |= startPausingLocked(userLeaving, <span class="hljs-keyword">false</span>, <span class="hljs-keyword">true</span>, dontWaitForPause);
}
<span class="hljs-keyword">if</span> (pausing) {
    <span class="hljs-keyword">if</span> (DEBUG_SWITCH || DEBUG_STATES) Slog.v(TAG_STATES,
            <span class="hljs-string">"resumeTopActivityLocked: Skip resume: need to start pausing"</span>);
    <span class="hljs-comment">// At this point we want to put the upcoming activity's process</span>
    <span class="hljs-comment">// at the top of the LRU list, since we know we will be needing it</span>
    <span class="hljs-comment">// very soon and it would be a waste to let it get killed if it</span>
    <span class="hljs-comment">// happens to be sitting towards the end.</span>
    <span class="hljs-keyword">if</span> (next.app != <span class="hljs-keyword">null</span> && next.app.thread != <span class="hljs-keyword">null</span>) {
        mService.updateLruProcessLocked(next.app, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">null</span>);
    }
    <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

再启动新的activity之前,需要把当前的这个activity pause掉才行。另外如果前一个已经开始pause了,那么我们就把当前activity所在的app进程加入到LRU中去,关于这块的请参考我的博客Android ActivityManagerService(AMS)的进程管理

<code class="hljs cs has-numbering"><span class="hljs-comment">// If the most recent activity was noHistory but was only stopped rather</span>
<span class="hljs-comment">// than stopped+finished because the device went to sleep, we need to make</span>
<span class="hljs-comment">// sure to finish it as we're making a new activity topmost.</span>
<span class="hljs-keyword">if</span> (mService.isSleeping() && mLastNoHistoryActivity != <span class="hljs-keyword">null</span> &&
       !mLastNoHistoryActivity.finishing) {
   <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES,
           <span class="hljs-string">"no-history finish of "</span> + mLastNoHistoryActivity + <span class="hljs-string">" on new resume"</span>);
   requestFinishActivityLocked(mLastNoHistoryActivity.appToken, Activity.RESULT_CANCELED,
           <span class="hljs-keyword">null</span>, <span class="hljs-string">"resume-no-history"</span>, <span class="hljs-keyword">false</span>);
   mLastNoHistoryActivity = <span class="hljs-keyword">null</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>

如果当前在前台的activity是使用了FLAG_ACTIVITY_NO_HISTORY标记或者设置了noHistory属性的话,那么如果当前系统即将睡眠的话,那就将这个activity直接finish掉。

<code class="hljs cs has-numbering"><span class="hljs-keyword">if</span> (prev != <span class="hljs-keyword">null</span> && prev != next) {
    <span class="hljs-keyword">if</span> (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
            && next != <span class="hljs-keyword">null</span> && !next.nowVisible) {
        mStackSupervisor.mWaitingVisibleActivities.add(prev);
        <span class="hljs-keyword">if</span> (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                <span class="hljs-string">"Resuming top, waiting visible to hide: "</span> + prev);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// The next activity is already visible, so hide the previous</span>
        <span class="hljs-comment">// activity's windows right now so we can show the new one ASAP.</span>
        <span class="hljs-comment">// We only do this if the previous is finishing, which should mean</span>
        <span class="hljs-comment">// it is on top of the one being resumed so hiding it quickly</span>
        <span class="hljs-comment">// is good.  Otherwise, we want to do the normal route of allowing</span>
        <span class="hljs-comment">// the resumed activity to be shown so we can decide if the</span>
        <span class="hljs-comment">// previous should actually be hidden depending on whether the</span>
        <span class="hljs-comment">// new one is found to be full-screen or not.</span>
        <span class="hljs-keyword">if</span> (prev.finishing) {
            mWindowManager.setAppVisibility(prev.appToken, <span class="hljs-keyword">false</span>);
            <span class="hljs-keyword">if</span> (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                    <span class="hljs-string">"Not waiting for visible to hide: "</span> + prev + <span class="hljs-string">", waitingVisible="</span>
                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    + <span class="hljs-string">", nowVisible="</span> + next.nowVisible);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">if</span> (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                    <span class="hljs-string">"Previous already visible but still waiting to hide: "</span> + prev
                    + <span class="hljs-string">", waitingVisible="</span>
                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    + <span class="hljs-string">", nowVisible="</span> + next.nowVisible);
        }
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li></ul>

如果之前的一个activity没有在等待可见的列表中,也就是说此时我们的activity还不可见,那就把前一个activity加入mWaitingVisibleActivities列表;相反,如果activity已经是可以看见的状态,则需要把前一个隐藏起来。

<code class="hljs cs has-numbering"><span class="hljs-comment">// Launching this app's activity, make sure the app is no longer</span>
<span class="hljs-comment">// considered stopped.</span>
<span class="hljs-keyword">try</span> {
    AppGlobals.getPackageManager().setPackageStoppedState(
            next.packageName, <span class="hljs-keyword">false</span>, next.userId); <span class="hljs-comment">/* TODO: Verify if correct userid */</span>
} <span class="hljs-keyword">catch</span> (RemoteException e1) {
} <span class="hljs-keyword">catch</span> (IllegalArgumentException e) {
    Slog.w(TAG, <span class="hljs-string">"Failed trying to unstop package "</span>
            + next.packageName + <span class="hljs-string">": "</span> + e);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>

通过PackageManagerService将当前activity的包状态设置为非stop状态。

<code class="hljs lua has-numbering">// We are starting up the <span class="hljs-built_in">next</span> activity, so tell the window manager
// that the previous one will be hidden soon.  This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = <span class="hljs-keyword">true</span>;
<span class="hljs-keyword">if</span> (prev != null) {
    <span class="hljs-keyword">if</span> (prev.finishing) {
        <span class="hljs-keyword">if</span> (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                <span class="hljs-string">"Prepare close transition: prev="</span> + prev);
        <span class="hljs-keyword">if</span> (mNoAnimActivities.contains(prev)) {
            anim = <span class="hljs-keyword">false</span>;
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, <span class="hljs-keyword">false</span>);
        } <span class="hljs-keyword">else</span> {
            mWindowManager.prepareAppTransition(prev.task == <span class="hljs-built_in">next</span>.task
                    ? AppTransition.TRANSIT_ACTIVITY_CLOSE
                    : AppTransition.TRANSIT_TASK_CLOSE, <span class="hljs-keyword">false</span>);
        }
        mWindowManager.setAppWillBeHidden(prev.appToken);
        mWindowManager.setAppVisibility(prev.appToken, <span class="hljs-keyword">false</span>);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                <span class="hljs-string">"Prepare open transition: prev="</span> + prev);
        <span class="hljs-keyword">if</span> (mNoAnimActivities.contains(<span class="hljs-built_in">next</span>)) {
            anim = <span class="hljs-keyword">false</span>;
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, <span class="hljs-keyword">false</span>);
        } <span class="hljs-keyword">else</span> {
            mWindowManager.prepareAppTransition(prev.task == <span class="hljs-built_in">next</span>.task
                    ? AppTransition.TRANSIT_ACTIVITY_OPEN
                    : <span class="hljs-built_in">next</span>.mLaunchTaskBehind
                            ? AppTransition.TRANSIT_TASK_OPEN_BEHIND
                            : AppTransition.TRANSIT_TASK_OPEN, <span class="hljs-keyword">false</span>);
        }
    }
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">false</span>) {
        mWindowManager.setAppWillBeHidden(prev.appToken);
        mWindowManager.setAppVisibility(prev.appToken, <span class="hljs-keyword">false</span>);
    }
} <span class="hljs-keyword">else</span> {
    <span class="hljs-keyword">if</span> (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, <span class="hljs-string">"Prepare open transition: no previous"</span>);
    <span class="hljs-keyword">if</span> (mNoAnimActivities.contains(<span class="hljs-built_in">next</span>)) {
        anim = <span class="hljs-keyword">false</span>;
        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, <span class="hljs-keyword">false</span>);
    } <span class="hljs-keyword">else</span> {
        mWindowManager.prepareAppTransition(AppTransition.TRANSIT_ACTIVITY_OPEN, <span class="hljs-keyword">false</span>);
    }
}

Bundle resumeAnimOptions = null;
<span class="hljs-keyword">if</span> (anim) {
    ActivityOptions opts = <span class="hljs-built_in">next</span>.getOptionsForTargetActivityLocked();
    <span class="hljs-keyword">if</span> (opts != null) {
        resumeAnimOptions = opts.toBundle();
    }
    <span class="hljs-built_in">next</span>.applyOptionsLocked();
} <span class="hljs-keyword">else</span> {
    <span class="hljs-built_in">next</span>.clearOptionsLocked();
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li></ul>

这里我们通过WMS将前一个activity隐藏起来,这里通过WMS设置了一系列按照app设置的过渡动画效果。

<code class="hljs perl has-numbering">ActivityStack lastStack = mStackSupervisor.getLastStack();
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">next</span>.app != null && <span class="hljs-keyword">next</span>.app.thread != null) {
    <span class="hljs-keyword">if</span> (DEBUG_SWITCH) Slog.v(TAG_SWITCH, <span class="hljs-string">"Resume running: "</span> + <span class="hljs-keyword">next</span>);

    <span class="hljs-regexp">//</span> This activity is now becoming visible.
    mWindowManager.setAppVisibility(<span class="hljs-keyword">next</span>.appToken, true);

    <span class="hljs-regexp">//</span> schedule launch ticks to collect information about slow apps.
    <span class="hljs-keyword">next</span>.startLaunchTickingLocked();

    ActivityRecord lastResumedActivity =
            lastStack == null ? null :lastStack.mResumedActivity;
    ActivityState lastState = <span class="hljs-keyword">next</span>.<span class="hljs-keyword">state</span>;

    mService.updateCpuStats();

    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.v(TAG_STATES, <span class="hljs-string">"Moving to RESUMED: "</span> + <span class="hljs-keyword">next</span> + <span class="hljs-string">" (in existing)"</span>);
    <span class="hljs-keyword">next</span>.<span class="hljs-keyword">state</span> = ActivityState.RESUMED;
    mResumedActivity = <span class="hljs-keyword">next</span>;
    <span class="hljs-keyword">next</span>.task.touchActiveTime();
    mRecentTasks.addLocked(<span class="hljs-keyword">next</span>.task);
    mService.updateLruProcessLocked(<span class="hljs-keyword">next</span>.app, true, null);
    updateLRUListLocked(<span class="hljs-keyword">next</span>);
    mService.updateOomAdjLocked();

    <span class="hljs-regexp">//</span> Have the window manager re-evaluate the orientation of
    // the screen based on the new activity order.
    boolean notUpdated = true;
    <span class="hljs-keyword">if</span> (mStackSupervisor.isFrontStack(this)) {
        Configuration config = mWindowManager.updateOrientationFromAppTokens(
                mService.mConfiguration,
                <span class="hljs-keyword">next</span>.mayFreezeScreenLocked(<span class="hljs-keyword">next</span>.app) ? <span class="hljs-keyword">next</span>.appToken : null);
        <span class="hljs-keyword">if</span> (config != null) {
            <span class="hljs-keyword">next</span>.frozenBeforeDestroy = true;
        }
        notUpdated = !mService.updateConfigurationLocked(config, <span class="hljs-keyword">next</span>, false, false);
    }

    <span class="hljs-keyword">if</span> (notUpdated) {
        <span class="hljs-regexp">//</span> The configuration update wasn<span class="hljs-string">'t able to keep the existing
        // instance of the activity, and instead started a new one.
        // We should be all done, but let'</span><span class="hljs-keyword">s</span> just make sure <span class="hljs-keyword">our</span> activity
        // is still at the top <span class="hljs-keyword">and</span> schedule another run <span class="hljs-keyword">if</span> something
        // weird happened.
        ActivityRecord nextNext = topRunningActivityLocked(null);
        <span class="hljs-keyword">if</span> (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_STATES,
                <span class="hljs-string">"Activity config changed during resume: "</span> + <span class="hljs-keyword">next</span>
                + <span class="hljs-string">", new next: "</span> + nextNext);
        <span class="hljs-keyword">if</span> (nextNext != <span class="hljs-keyword">next</span>) {
            <span class="hljs-regexp">//</span> Do over!
            mStackSupervisor.scheduleResumeTopActivities();
        }
        <span class="hljs-keyword">if</span> (mStackSupervisor.reportResumedActivityLocked(<span class="hljs-keyword">next</span>)) {
            mNoAnimActivities.clear();
            <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            <span class="hljs-keyword">return</span> true;
        }
        <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        <span class="hljs-keyword">return</span> false;
    }

    try {
        <span class="hljs-regexp">//</span> Deliver all pending results.
        ArrayList<ResultInfo> a = <span class="hljs-keyword">next</span>.results;
        <span class="hljs-keyword">if</span> (a != null) {
            final <span class="hljs-keyword">int</span> N = a.size();
            <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">next</span>.finishing && N > <span class="hljs-number">0</span>) {
                <span class="hljs-keyword">if</span> (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
                        <span class="hljs-string">"Delivering results to "</span> + <span class="hljs-keyword">next</span> + <span class="hljs-string">": "</span> + a);
                <span class="hljs-keyword">next</span>.app.thread.scheduleSendResult(<span class="hljs-keyword">next</span>.appToken, a);
            }
        }

        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">next</span>.newIntents != null) {
            <span class="hljs-keyword">next</span>.app.thread.scheduleNewIntent(<span class="hljs-keyword">next</span>.newIntents, <span class="hljs-keyword">next</span>.appToken);
        }

        EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, <span class="hljs-keyword">next</span>.userId,
                System.identityHashCode(<span class="hljs-keyword">next</span>), <span class="hljs-keyword">next</span>.task.taskId, <span class="hljs-keyword">next</span>.shortComponentName);

        <span class="hljs-keyword">next</span>.sleeping = false;
        mService.showAskCompatModeDialogLocked(<span class="hljs-keyword">next</span>);
        <span class="hljs-keyword">next</span>.app.pendingUiClean = true;
        <span class="hljs-keyword">next</span>.app.forceProcessStateUpTo(mService.mTopProcessState);
        <span class="hljs-keyword">next</span>.clearOptionsLocked();
        <span class="hljs-keyword">next</span>.app.thread.scheduleResumeActivity(<span class="hljs-keyword">next</span>.appToken, <span class="hljs-keyword">next</span>.app.repProcState,
                mService.isNextTransitionForward(), resumeAnimOptions);

        mStackSupervisor.checkReadyForSleepLocked();

        <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES, <span class="hljs-string">"resumeTopActivityLocked: Resumed "</span> + <span class="hljs-keyword">next</span>);
    } catch (Exception e) {
        <span class="hljs-regexp">//</span> Whoops, need to restart this activity!
        <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.v(TAG_STATES, <span class="hljs-string">"Resume failed; resetting state to "</span>
                + lastState + <span class="hljs-string">": "</span> + <span class="hljs-keyword">next</span>);
        <span class="hljs-keyword">next</span>.<span class="hljs-keyword">state</span> = lastState;
        <span class="hljs-keyword">if</span> (lastStack != null) {
            lastStack.mResumedActivity = lastResumedActivity;
        }
        Slog.i(TAG, <span class="hljs-string">"Restarting because process died: "</span> + <span class="hljs-keyword">next</span>);
        <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">next</span>.hasBeenLaunched) {
            <span class="hljs-keyword">next</span>.hasBeenLaunched = true;
        } <span class="hljs-keyword">else</span>  <span class="hljs-keyword">if</span> (SHOW_APP_STARTING_PREVIEW && lastStack != null &&
                mStackSupervisor.isFrontStack(lastStack)) {
            mWindowManager.setAppStartingWindow(
                    <span class="hljs-keyword">next</span>.appToken, <span class="hljs-keyword">next</span>.packageName, <span class="hljs-keyword">next</span>.theme,
                    mService.compatibilityInfoForPackageLocked(<span class="hljs-keyword">next</span>.info.applicationInfo),
                    <span class="hljs-keyword">next</span>.nonLocalizedLabel, <span class="hljs-keyword">next</span>.labelRes, <span class="hljs-keyword">next</span>.icon, <span class="hljs-keyword">next</span>.logo,
                    <span class="hljs-keyword">next</span>.windowFlags, null, true);
        }
        mStackSupervisor.startSpecificActivityLocked(<span class="hljs-keyword">next</span>, true, false);
        <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        <span class="hljs-keyword">return</span> true;
    }

    // From this point on, <span class="hljs-keyword">if</span> something goes wrong there is <span class="hljs-keyword">no</span> way
    // to recover the activity.
    try {
        <span class="hljs-keyword">next</span>.visible = true;
        completeResumeLocked(<span class="hljs-keyword">next</span>);
    } catch (Exception e) {
        <span class="hljs-regexp">//</span> If any exception gets thrown, toss away this
        // activity <span class="hljs-keyword">and</span> try the <span class="hljs-keyword">next</span> one.
        Slog.w(TAG, <span class="hljs-string">"Exception thrown during resume of "</span> + <span class="hljs-keyword">next</span>, e);
        requestFinishActivityLocked(<span class="hljs-keyword">next</span>.appToken, Activity.RESULT_CANCELED, null,
                <span class="hljs-string">"resume-exception"</span>, true);
        <span class="hljs-keyword">if</span> (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
        <span class="hljs-keyword">return</span> true;
    }
    <span class="hljs-keyword">next</span>.stopped = false;

} <span class="hljs-keyword">else</span> {
    <span class="hljs-regexp">//</span> Whoops, need to restart this activity!
    <span class="hljs-keyword">if</span> (!<span class="hljs-keyword">next</span>.hasBeenLaunched) {
        <span class="hljs-keyword">next</span>.hasBeenLaunched = true;
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">if</span> (SHOW_APP_STARTING_PREVIEW) {
            mWindowManager.setAppStartingWindow(
                    <span class="hljs-keyword">next</span>.appToken, <span class="hljs-keyword">next</span>.packageName, <span class="hljs-keyword">next</span>.theme,
                    mService.compatibilityInfoForPackageLocked(
                            <span class="hljs-keyword">next</span>.info.applicationInfo),
                    <span class="hljs-keyword">next</span>.nonLocalizedLabel,
                    <span class="hljs-keyword">next</span>.labelRes, <span class="hljs-keyword">next</span>.icon, <span class="hljs-keyword">next</span>.logo, <span class="hljs-keyword">next</span>.windowFlags,
                    null, true);
        }
        <span class="hljs-keyword">if</span> (DEBUG_SWITCH) Slog.v(TAG_SWITCH, <span class="hljs-string">"Restarting: "</span> + <span class="hljs-keyword">next</span>);
    }
    <span class="hljs-keyword">if</span> (DEBUG_STATES) Slog.d(TAG_STATES, <span class="hljs-string">"resumeTopActivityLocked: Restarting "</span> + <span class="hljs-keyword">next</span>);
    mStackSupervisor.startSpecificActivityLocked(<span class="hljs-keyword">next</span>, true, true);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li><li>137</li><li>138</li><li>139</li><li>140</li><li>141</li><li>142</li><li>143</li><li>144</li><li>145</li><li>146</li><li>147</li><li>148</li><li>149</li><li>150</li></ul>

这段代码调用WMS的方法来处理activity的显示,如果activity所在的进程的已经存在,那么只要把activity显示出来就可以了,直接回调应用的onNewIntent方法,之后调用activity的onResume;如果activity所在进程暂时不存在的话,就先调用startSpecificActivityLocked启动相应的进程。
到这里resumeTopActivityInnerLocked就基本分析完了,这个方法虽然比较长,但是没有十分复杂的逻辑,都是按照正常的启动流程在操作。上面我们提到了如果activity所在的进程不存在的话,那么我们会调用startSpecificActivityLocked方法来启动相应进程:
startSpecificActivityLocked@ActivityStackSupervisor.java

<code class="hljs java has-numbering"><span class="hljs-keyword">void</span> startSpecificActivityLocked(ActivityRecord r,
        <span class="hljs-keyword">boolean</span> andResume, <span class="hljs-keyword">boolean</span> checkConfig) {
    <span class="hljs-comment">// Is this activity's application already running?</span>
    <span class="hljs-comment">// 通过AMS查找进程记录,得到进程是不是已经启动并且正在运行。</span>
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, <span class="hljs-keyword">true</span>);

    r.task.stack.setLaunchTime(r);

    <span class="hljs-comment">// 如果app == null的话,说明进程目前不存在;如果app.thread == null的话,说明进程正在启动。</span>
    <span class="hljs-keyword">if</span> (app != <span class="hljs-keyword">null</span> && app.thread != <span class="hljs-keyword">null</span>) {
        <span class="hljs-keyword">try</span> {
            <span class="hljs-keyword">if</span> ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == <span class="hljs-number">0</span>
                    || !<span class="hljs-string">"android"</span>.equals(r.info.packageName)) {
                <span class="hljs-comment">// Don't add this if it is a platform component that is marked</span>
                <span class="hljs-comment">// to run in multiple processes, because this is actually</span>
                <span class="hljs-comment">// part of the framework so doesn't make sense to track as a</span>
                <span class="hljs-comment">// separate apk in the process.</span>
                app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                        mService.mProcessStats);
            }
            <span class="hljs-comment">// 真正启动activity的地方</span>
            realStartActivityLocked(r, app, andResume, checkConfig);
            <span class="hljs-keyword">return</span>;
        } <span class="hljs-keyword">catch</span> (RemoteException e) {
            Slog.w(TAG, <span class="hljs-string">"Exception when starting activity "</span>
                    + r.intent.getComponent().flattenToShortString(), e);
        }

        <span class="hljs-comment">// If a dead object exception was thrown -- fall through to</span>
        <span class="hljs-comment">// restart the application.</span>
    }

    <span class="hljs-comment">// 程序走到这里说明进程不存在或者正在启动,因此需要先启动进程。</span>
    mService.startProcessLocked(r.processName, r.info.applicationInfo, <span class="hljs-keyword">true</span>, <span class="hljs-number">0</span>,
            <span class="hljs-string">"activity"</span>, r.intent.getComponent(), <span class="hljs-keyword">false</span>, <span class="hljs-keyword">false</span>, <span class="hljs-keyword">true</span>);
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li></ul>

上面程序的逻辑很清楚,就是如果进程存在并且已经启动完毕,那么就直接启动activity,否则就先启动进程,然后在启动对应的activity。这里的startProcessLocked方法就是用于启动对应的进程的,关于AMS进程的启动和管理在我的Android ActivityManagerService(AMS)的进程管理这篇博客中已经有详述,这里就不赘述。
下面我们把重点放在realStartActivityLocked这个方法上,这个方法中核心就是调用了ApplicationThread的scheduleLaunchActivity方法启动activity:
scheduleLaunchActivity@ApplicationThread

<code class="hljs avrasm has-numbering">// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
        ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
        CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
        int procState, Bundle state, PersistableBundle persistentState,
        List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
        boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

    updateProcessState(procState, false)<span class="hljs-comment">;</span>

    ActivityClientRecord r = new ActivityClientRecord()<span class="hljs-comment">;</span>

    r<span class="hljs-preprocessor">.token</span> = token<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.ident</span> = ident<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.intent</span> = intent<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.referrer</span> = referrer<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.voiceInteractor</span> = voiceInteractor<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.activityInfo</span> = info<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.compatInfo</span> = compatInfo<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.state</span> = state<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.persistentState</span> = persistentState<span class="hljs-comment">;</span>

    r<span class="hljs-preprocessor">.pendingResults</span> = pendingResults<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.pendingIntents</span> = pendingNewIntents<span class="hljs-comment">;</span>

    r<span class="hljs-preprocessor">.startsNotResumed</span> = notResumed<span class="hljs-comment">;</span>
    r<span class="hljs-preprocessor">.isForward</span> = isForward<span class="hljs-comment">;</span>

    r<span class="hljs-preprocessor">.profilerInfo</span> = profilerInfo<span class="hljs-comment">;</span>

    r<span class="hljs-preprocessor">.overrideConfig</span> = overrideConfig<span class="hljs-comment">;</span>
    updatePendingConfiguration(curConfig)<span class="hljs-comment">;</span>

    sendMessage(H<span class="hljs-preprocessor">.LAUNCH</span>_ACTIVITY, r)<span class="hljs-comment">;</span>
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li></ul>

我们前面说过,ApplicationThread都是通过message的方式和ActivityThread通讯的,实际消息处理由ActivityThread中的Handler处理:

<code class="hljs avrasm has-numbering">public void handleMessage(Message msg) {
    if (DEBUG_MESSAGES) Slog<span class="hljs-preprocessor">.v</span>(TAG, <span class="hljs-string">">>> handling: "</span> + codeToString(msg<span class="hljs-preprocessor">.what</span>))<span class="hljs-comment">;</span>
    switch (msg<span class="hljs-preprocessor">.what</span>) {
        case LAUNCH_ACTIVITY: {
            Trace<span class="hljs-preprocessor">.traceBegin</span>(Trace<span class="hljs-preprocessor">.TRACE</span>_TAG_ACTIVITY_MANAGER, <span class="hljs-string">"activityStart"</span>)<span class="hljs-comment">;</span>
            final ActivityClientRecord r = (ActivityClientRecord) msg<span class="hljs-preprocessor">.obj</span><span class="hljs-comment">;</span>

            r<span class="hljs-preprocessor">.packageInfo</span> = getPackageInfoNoCheck(
                    r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.applicationInfo</span>, r<span class="hljs-preprocessor">.compatInfo</span>)<span class="hljs-comment">;</span>
            // 处理activity的启动
            handleLaunchActivity(r, null)<span class="hljs-comment">;</span>
            Trace<span class="hljs-preprocessor">.traceEnd</span>(Trace<span class="hljs-preprocessor">.TRACE</span>_TAG_ACTIVITY_MANAGER)<span class="hljs-comment">;</span>
        } <span class="hljs-keyword">break</span><span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

这里调用了handleLaunchActivity处理activity的启动:
handleLaunchActivity@ActivityThread.java

<code class="hljs cs has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleLaunchActivity</span>(ActivityClientRecord r, Intent customIntent) {
    <span class="hljs-comment">// If we are getting ready to gc after going to the background, well</span>
    <span class="hljs-comment">// we are back active so skip it.</span>
    unscheduleGcIdler();
    mSomeActivitiesChanged = <span class="hljs-keyword">true</span>;

    <span class="hljs-keyword">if</span> (r.profilerInfo != <span class="hljs-keyword">null</span>) {
        mProfiler.setProfiler(r.profilerInfo);
        mProfiler.startProfiling();
    }

    <span class="hljs-comment">// Make sure we are running with the most recent config.</span>
    <span class="hljs-comment">// 更新当前activity的配置(包括屏幕方向,尺寸等),保证使用最新的配置</span>
    handleConfigurationChanged(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>);

    <span class="hljs-keyword">if</span> (localLOGV) Slog.v(
        TAG, <span class="hljs-string">"Handling launch of "</span> + r);

    <span class="hljs-comment">// Initialize before creating the activity</span>
    WindowManagerGlobal.initialize();

    <span class="hljs-comment">// 这里实际启动了activity,会回调onCreate方法</span>
    Activity a = performLaunchActivity(r, customIntent);

    <span class="hljs-keyword">if</span> (a != <span class="hljs-keyword">null</span>) {
        r.createdConfig = <span class="hljs-keyword">new</span> Configuration(mConfiguration);
        Bundle oldState = r.state;
        <span class="hljs-comment">// resume目标activity,会回调onResume方法</span>
        handleResumeActivity(r.token, <span class="hljs-keyword">false</span>, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        <span class="hljs-keyword">if</span> (!r.activity.mFinished && r.startsNotResumed) {
            <span class="hljs-comment">// The activity manager actually wants this one to start out</span>
            <span class="hljs-comment">// paused, because it needs to be visible but isn't in the</span>
            <span class="hljs-comment">// foreground.  We accomplish this by going through the</span>
            <span class="hljs-comment">// normal startup (because activities expect to go through</span>
            <span class="hljs-comment">// onResume() the first time they run, before their window</span>
            <span class="hljs-comment">// is displayed), and then pausing it.  However, in this case</span>
            <span class="hljs-comment">// we do -not- need to do the full pause cycle (of freezing</span>
            <span class="hljs-comment">// and such) because the activity manager assumes it can just</span>
            <span class="hljs-comment">// retain the current state it has.</span>
            <span class="hljs-comment">// 将启动这个activity的activity pause,因为当前activity要启动了,需要遮住之前的activity。</span>
            <span class="hljs-keyword">try</span> {
                r.activity.mCalled = <span class="hljs-keyword">false</span>;
                mInstrumentation.callActivityOnPause(r.activity);
                <span class="hljs-comment">// We need to keep around the original state, in case</span>
                <span class="hljs-comment">// we need to be created again.  But we only do this</span>
                <span class="hljs-comment">// for pre-Honeycomb apps, which always save their state</span>
                <span class="hljs-comment">// when pausing, so we can not have them save their state</span>
                <span class="hljs-comment">// when restarting from a paused state.  For HC and later,</span>
                <span class="hljs-comment">// we want to (and can) let the state be saved as the normal</span>
                <span class="hljs-comment">// part of stopping the activity.</span>
                <span class="hljs-keyword">if</span> (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
                <span class="hljs-keyword">if</span> (!r.activity.mCalled) {
                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> SuperNotCalledException(
                        <span class="hljs-string">"Activity "</span> + r.intent.getComponent().toShortString() +
                        <span class="hljs-string">" did not call through to super.onPause()"</span>);
                }

            } <span class="hljs-keyword">catch</span> (SuperNotCalledException e) {
                <span class="hljs-keyword">throw</span> e;

            } <span class="hljs-keyword">catch</span> (Exception e) {
                <span class="hljs-keyword">if</span> (!mInstrumentation.onException(r.activity, e)) {
                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(
                            <span class="hljs-string">"Unable to pause activity "</span>
                            + r.intent.getComponent().toShortString()
                            + <span class="hljs-string">": "</span> + e.toString(), e);
                }
            }
            r.paused = <span class="hljs-keyword">true</span>;
        }
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-comment">// If there was an error, for any reason, tell the activity</span>
        <span class="hljs-comment">// manager to stop us.</span>
        <span class="hljs-keyword">try</span> {
            ActivityManagerNative.getDefault()
                .finishActivity(r.token, Activity.RESULT_CANCELED, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">false</span>);
        } <span class="hljs-keyword">catch</span> (RemoteException ex) {
            <span class="hljs-comment">// Ignore</span>
        }
    }
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li></ul>

我们看到上面主要的就是performLaunchActivity这步操作了,我们看下这个方法的实现:
performLaunchActivity@ActivityThread.java

<code class="hljs avrasm has-numbering">private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ActivityInfo aInfo = r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-comment">;</span>
    if (r<span class="hljs-preprocessor">.packageInfo</span> == null) {
        r<span class="hljs-preprocessor">.packageInfo</span> = getPackageInfo(aInfo<span class="hljs-preprocessor">.applicationInfo</span>, r<span class="hljs-preprocessor">.compatInfo</span>,
                Context<span class="hljs-preprocessor">.CONTEXT</span>_INCLUDE_CODE)<span class="hljs-comment">;</span>
    }

    ComponentName component = r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.getComponent</span>()<span class="hljs-comment">;</span>
    if (component == null) {
        component = r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.resolveActivity</span>(
            mInitialApplication<span class="hljs-preprocessor">.getPackageManager</span>())<span class="hljs-comment">;</span>
        r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.setComponent</span>(component)<span class="hljs-comment">;</span>
    }

    if (r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.targetActivity</span> != null) {
        component = new ComponentName(r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.packageName</span>,
                r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.targetActivity</span>)<span class="hljs-comment">;</span>
    }

    Activity activity = null<span class="hljs-comment">;</span>
    // 实例化activity对象
    try {
        java<span class="hljs-preprocessor">.lang</span><span class="hljs-preprocessor">.ClassLoader</span> cl = r<span class="hljs-preprocessor">.packageInfo</span><span class="hljs-preprocessor">.getClassLoader</span>()<span class="hljs-comment">;</span>
        activity = mInstrumentation<span class="hljs-preprocessor">.newActivity</span>(
                cl, component<span class="hljs-preprocessor">.getClassName</span>(), r<span class="hljs-preprocessor">.intent</span>)<span class="hljs-comment">;</span>
        StrictMode<span class="hljs-preprocessor">.incrementExpectedActivityCount</span>(activity<span class="hljs-preprocessor">.getClass</span>())<span class="hljs-comment">;</span>
        r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.setExtrasClassLoader</span>(cl)<span class="hljs-comment">;</span>
        r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.prepareToEnterProcess</span>()<span class="hljs-comment">;</span>
        if (r<span class="hljs-preprocessor">.state</span> != null) {
            r<span class="hljs-preprocessor">.state</span><span class="hljs-preprocessor">.setClassLoader</span>(cl)<span class="hljs-comment">;</span>
        }
    } catch (Exception e) {
        if (!mInstrumentation<span class="hljs-preprocessor">.onException</span>(activity, e)) {
            throw new RuntimeException(
                <span class="hljs-string">"Unable to instantiate activity "</span> + component
                + <span class="hljs-string">": "</span> + e<span class="hljs-preprocessor">.toString</span>(), e)<span class="hljs-comment">;</span>
        }
    }

    try {
        Application app = r<span class="hljs-preprocessor">.packageInfo</span><span class="hljs-preprocessor">.makeApplication</span>(false, mInstrumentation)<span class="hljs-comment">;</span>

        if (localLOGV) Slog<span class="hljs-preprocessor">.v</span>(TAG, <span class="hljs-string">"Performing launch of "</span> + r)<span class="hljs-comment">;</span>
        if (localLOGV) Slog<span class="hljs-preprocessor">.v</span>(
                TAG, r + <span class="hljs-string">": app="</span> + app
                + <span class="hljs-string">", appName="</span> + app<span class="hljs-preprocessor">.getPackageName</span>()
                + <span class="hljs-string">", pkg="</span> + r<span class="hljs-preprocessor">.packageInfo</span><span class="hljs-preprocessor">.getPackageName</span>()
                + <span class="hljs-string">", comp="</span> + r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.getComponent</span>()<span class="hljs-preprocessor">.toShortString</span>()
                + <span class="hljs-string">", dir="</span> + r<span class="hljs-preprocessor">.packageInfo</span><span class="hljs-preprocessor">.getAppDir</span>())<span class="hljs-comment">;</span>

        if (activity != null) {
            // 实例化context
            Context appContext = createBaseContextForActivity(r, activity)<span class="hljs-comment">;</span>
            CharSequence title = r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.loadLabel</span>(appContext<span class="hljs-preprocessor">.getPackageManager</span>())<span class="hljs-comment">;</span>
            Configuration config = new Configuration(mCompatConfiguration)<span class="hljs-comment">;</span>
            if (DEBUG_CONFIGURATION) Slog<span class="hljs-preprocessor">.v</span>(TAG, <span class="hljs-string">"Launching activity "</span>
                    + r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.name</span> + <span class="hljs-string">" with config "</span> + config)<span class="hljs-comment">;</span>
            // 将activity和进程进行关系关联
            activity<span class="hljs-preprocessor">.attach</span>(appContext, this, getInstrumentation(), r<span class="hljs-preprocessor">.token</span>,
                    r<span class="hljs-preprocessor">.ident</span>, app, r<span class="hljs-preprocessor">.intent</span>, r<span class="hljs-preprocessor">.activityInfo</span>, title, r<span class="hljs-preprocessor">.parent</span>,
                    r<span class="hljs-preprocessor">.embeddedID</span>, r<span class="hljs-preprocessor">.lastNonConfigurationInstances</span>, config,
                    r<span class="hljs-preprocessor">.referrer</span>, r<span class="hljs-preprocessor">.voiceInteractor</span>)<span class="hljs-comment">;</span>

            if (customIntent != null) {
                activity<span class="hljs-preprocessor">.mIntent</span> = customIntent<span class="hljs-comment">;</span>
            }
            r<span class="hljs-preprocessor">.lastNonConfigurationInstances</span> = null<span class="hljs-comment">;</span>
            activity<span class="hljs-preprocessor">.mStartedActivity</span> = false<span class="hljs-comment">;</span>
            int theme = r<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-preprocessor">.getThemeResource</span>()<span class="hljs-comment">;</span>
            if (theme != <span class="hljs-number">0</span>) {
                activity<span class="hljs-preprocessor">.setTheme</span>(theme)<span class="hljs-comment">;</span>
            }

            activity<span class="hljs-preprocessor">.mCalled</span> = false<span class="hljs-comment">;</span>
            if (r<span class="hljs-preprocessor">.isPersistable</span>()) {
                // 这里回调activity的onCreate方法
                mInstrumentation<span class="hljs-preprocessor">.callActivityOnCreate</span>(activity, r<span class="hljs-preprocessor">.state</span>, r<span class="hljs-preprocessor">.persistentState</span>)<span class="hljs-comment">;</span>
            } else {
                mInstrumentation<span class="hljs-preprocessor">.callActivityOnCreate</span>(activity, r<span class="hljs-preprocessor">.state</span>)<span class="hljs-comment">;</span>
            }
            if (!activity<span class="hljs-preprocessor">.mCalled</span>) {
                throw new SuperNotCalledException(
                    <span class="hljs-string">"Activity "</span> + r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.getComponent</span>()<span class="hljs-preprocessor">.toShortString</span>() +
                    <span class="hljs-string">" did not call through to super.onCreate()"</span>)<span class="hljs-comment">;</span>
            }
            r<span class="hljs-preprocessor">.activity</span> = activity<span class="hljs-comment">;</span>
            r<span class="hljs-preprocessor">.stopped</span> = true<span class="hljs-comment">;</span>
            if (!r<span class="hljs-preprocessor">.activity</span><span class="hljs-preprocessor">.mFinished</span>) {
                activity<span class="hljs-preprocessor">.performStart</span>()<span class="hljs-comment">;</span>
                r<span class="hljs-preprocessor">.stopped</span> = false<span class="hljs-comment">;</span>
            }
            if (!r<span class="hljs-preprocessor">.activity</span><span class="hljs-preprocessor">.mFinished</span>) {
                if (r<span class="hljs-preprocessor">.isPersistable</span>()) {
                    // 回调OnRestoreInstanceState方法,以便恢复之前activity的状态
                    if (r<span class="hljs-preprocessor">.state</span> != null || r<span class="hljs-preprocessor">.persistentState</span> != null) {
                        mInstrumentation<span class="hljs-preprocessor">.callActivityOnRestoreInstanceState</span>(activity, r<span class="hljs-preprocessor">.state</span>,
                                r<span class="hljs-preprocessor">.persistentState</span>)<span class="hljs-comment">;</span>
                    }
                } else if (r<span class="hljs-preprocessor">.state</span> != null) {
                    mInstrumentation<span class="hljs-preprocessor">.callActivityOnRestoreInstanceState</span>(activity, r<span class="hljs-preprocessor">.state</span>)<span class="hljs-comment">;</span>
                }
            }
            if (!r<span class="hljs-preprocessor">.activity</span><span class="hljs-preprocessor">.mFinished</span>) {
                activity<span class="hljs-preprocessor">.mCalled</span> = false<span class="hljs-comment">;</span>
                if (r<span class="hljs-preprocessor">.isPersistable</span>()) {
                    // 回调OnPostCreate方法
                    mInstrumentation<span class="hljs-preprocessor">.callActivityOnPostCreate</span>(activity, r<span class="hljs-preprocessor">.state</span>,
                            r<span class="hljs-preprocessor">.persistentState</span>)<span class="hljs-comment">;</span>
                } else {
                    mInstrumentation<span class="hljs-preprocessor">.callActivityOnPostCreate</span>(activity, r<span class="hljs-preprocessor">.state</span>)<span class="hljs-comment">;</span>
                }
                if (!activity<span class="hljs-preprocessor">.mCalled</span>) {
                    throw new SuperNotCalledException(
                        <span class="hljs-string">"Activity "</span> + r<span class="hljs-preprocessor">.intent</span><span class="hljs-preprocessor">.getComponent</span>()<span class="hljs-preprocessor">.toShortString</span>() +
                        <span class="hljs-string">" did not call through to super.onPostCreate()"</span>)<span class="hljs-comment">;</span>
                }
            }
        }
        r<span class="hljs-preprocessor">.paused</span> = true<span class="hljs-comment">;</span>

        // 将启动这个activity的请求者记录放到mActivities中,统一调度管理
        mActivities<span class="hljs-preprocessor">.put</span>(r<span class="hljs-preprocessor">.token</span>, r)<span class="hljs-comment">;</span>

    } catch (SuperNotCalledException e) {
        throw e<span class="hljs-comment">;</span>

    } catch (Exception e) {
        if (!mInstrumentation<span class="hljs-preprocessor">.onException</span>(activity, e)) {
            throw new RuntimeException(
                <span class="hljs-string">"Unable to start activity "</span> + component
                + <span class="hljs-string">": "</span> + e<span class="hljs-preprocessor">.toString</span>(), e)<span class="hljs-comment">;</span>
        }
    }

    return activity<span class="hljs-comment">;</span>
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li><li>111</li><li>112</li><li>113</li><li>114</li><li>115</li><li>116</li><li>117</li><li>118</li><li>119</li><li>120</li><li>121</li><li>122</li><li>123</li><li>124</li><li>125</li><li>126</li><li>127</li><li>128</li><li>129</li><li>130</li><li>131</li><li>132</li><li>133</li><li>134</li><li>135</li><li>136</li></ul>

这里我们看到了对activity启动初期的各种生命周期方法的回调。经过这个方法之后activity基本就创建完毕了,当时还没有显示出来,还需要在上面我们提到的handleLaunchActivity方法中继续调用handleResumeActivity去回调activity的onResume,并且做好显示前的最后准备工作才行。handleResumeActivity这个方法比较简单,大家可以自行看一下。
下面我们使用UML时序图的方式梳理一下AMS中activity的启动过程:
这里写图片描述
如果图片太小看不清楚的话,你可以右击选择独立窗口打开这张图片,或者直接下载这张图片,就可以放大查看了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 中,AMS(Activity Manager Service)负责管理 Activity 的生命周期。Activity 有四个状态:运行状态、暂停状态、停止状态和销毁状态。当一个 Activity 运行时,它可以被用户看到,并响应用户的交互;当它被暂停时,它被部分遮挡,但仍然在屏幕上存在;当它被停止时,它被完全遮挡,但其状态仍然保留在内存中;当它被销毁时,它被完全删除,其状态也从内存中释放。 Activity 生命周期管理的关键是回调方法。Android 系统提供了一组回调方法,使得开发者可以在 Activity 的不同状态下执行相应的操作。 以下是 Activity 生命周期的回调方法: 1. onCreate(): Activity 被创建时调用,通常用来完成界面的初始化和数据的加载。 2. onStart(): Activity 变为可见时调用,此时 Activity 进入运行状态。 3. onResume(): Activity 处于前台并处于运行状态时调用,此时 Activity 可以响应用户的交互。 4. onPause(): 当其他 Activity 显示在前台并且当前 Activity 处于可见状态时调用,此时 Activity 进入暂停状态。 5. onStop(): Activity 完全被遮挡时调用,此时 Activity 进入停止状态。 6. onRestart(): 当 Activity 从停止状态重新进入运行状态时调用。 7. onDestroy(): Activity 被销毁时调用,通常用来释放内存或资源。 开发者应根据自己的应用需求在这些回调方法中编写相应的业务逻辑,从而实现自己的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值