Android ActivityManagerService(AMS)的Activity管理
版权声明:本文为博主原创文章,未经博主允许不得转载。
对于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的启动过程:
如果图片太小看不清楚的话,你可以右击选择独立窗口打开这张图片,或者直接下载这张图片,就可以放大查看了。