Launcher进程启动过程剖析
<p>上一篇<a href="https://dorck.cn/2023/04/22/android-initialization/">文章</a>我们对 Android 系统启动过程做了一定了解,本文将继续分析 Launcher 进程的启动流程。</p>
<blockquote>
<p>本文基于 Android 13 最新代码来进行源码分析。</p>
</blockquote>
<h3 id="launcher-进程启动">Launcher 进程启动</h3>
<p>上文中,我们最终谈到了 <code class="language-plaintext highlighter-rouge">system_server</code> 进程的创建过程,并且该进程主要负责:</p>
<ul>
<li>创建系统服务管理器——SystemServiceManager</li>
<li>启动各种服务(AMS、PMS等)</li>
<li>开启 Looper 循环,等待其他线程发送消息并处理</li>
</ul>
<p>我们看一下 AMS 服务创建及配置这块实现:</p>
<blockquote>
<p><em>frameworks/base/services/java/com/android/server/SystemServer.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
</pre></td><td class="rouge-code"><pre><span class="c1">// Activity manager runs the show.</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="s">"StartActivityManager"</span><span class="o">);</span>
<span class="c1">// TODO: Might need to move after migration to WM.</span>
<span class="nc">ActivityTaskManagerService</span> <span class="n">atm</span> <span class="o">=</span> <span class="n">mSystemServiceManager</span><span class="o">.</span><span class="na">startService</span><span class="o">(</span>
<span class="nc">ActivityTaskManagerService</span><span class="o">.</span><span class="na">Lifecycle</span><span class="o">.</span><span class="na">class</span><span class="o">).</span><span class="na">getService</span><span class="o">();</span>
<span class="n">mActivityManagerService</span> <span class="o">=</span> <span class="nc">ActivityManagerService</span><span class="o">.</span><span class="na">Lifecycle</span><span class="o">.</span><span class="na">startService</span><span class="o">(</span>
<span class="n">mSystemServiceManager</span><span class="o">,</span> <span class="n">atm</span><span class="o">);</span>
<span class="n">mActivityManagerService</span><span class="o">.</span><span class="na">setSystemServiceManager</span><span class="o">(</span><span class="n">mSystemServiceManager</span><span class="o">);</span>
<span class="n">mActivityManagerService</span><span class="o">.</span><span class="na">setInstaller</span><span class="o">(</span><span class="n">installer</span><span class="o">);</span>
<span class="o">......</span>
<span class="c1">// We now tell the activity manager it is okay to run third party</span>
<span class="c1">// code. It will call back into us once it has gotten to the state</span>
<span class="c1">// where third party code can really run (but before it has actually</span>
<span class="c1">// started launching the initial applications), for us to complete our</span>
<span class="c1">// initialization.</span>
<span class="n">mActivityManagerService</span><span class="o">.</span><span class="na">systemReady</span><span class="o">(()</span> <span class="o">-></span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Making services ready"</span><span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="s">"StartActivityManagerReadyPhase"</span><span class="o">);</span>
<span class="n">mSystemServiceManager</span><span class="o">.</span><span class="na">startBootPhase</span><span class="o">(</span><span class="n">t</span><span class="o">,</span> <span class="nc">SystemService</span><span class="o">.</span><span class="na">PHASE_ACTIVITY_MANAGER_READY</span><span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">();</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="s">"StartObservingNativeCrashes"</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mActivityManagerService</span><span class="o">.</span><span class="na">startObservingNativeCrashes</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Throwable</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">reportWtf</span><span class="o">(</span><span class="s">"observing native crashes"</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">......</span>
<span class="o">},</span> <span class="n">t</span><span class="o">);</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>下面重点关注一下 <code class="language-plaintext highlighter-rouge">ActivityManagerService.systemReady</code> 方法,通过注释可以简单了解到 Launcher 应用貌似就是在这里启动的,来找一下代码实现:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="nf">ActivityManagerService</span><span class="o">(</span><span class="nc">Context</span> <span class="n">systemContext</span><span class="o">,</span> <span class="nc">ActivityTaskManagerService</span> <span class="n">atm</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="n">mAtmInternal</span> <span class="o">=</span> <span class="nc">LocalServices</span><span class="o">.</span><span class="na">getService</span><span class="o">(</span><span class="nc">ActivityTaskManagerInternal</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="cm">/**
* Ready. Set. Go!
*/</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">systemReady</span><span class="o">(</span><span class="kd">final</span> <span class="nc">Runnable</span> <span class="n">goingCallback</span><span class="o">,</span> <span class="nd">@NonNull</span> <span class="nc">TimingsTraceAndSlog</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="s">"PhaseActivityManagerReady"</span><span class="o">);</span>
<span class="n">mSystemServiceManager</span><span class="o">.</span><span class="na">preSystemReady</span><span class="o">();</span>
<span class="o">...</span>
<span class="c1">// Some systems - like automotive - will explicitly unlock system user then switch</span>
<span class="c1">// to a secondary user.</span>
<span class="c1">// TODO(b/242195409): this workaround shouldn't be necessary once we move</span>
<span class="c1">// the headless-user start logic to UserManager-land.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">isBootingSystemUser</span> <span class="o">&&</span> <span class="o">!</span><span class="nc">UserManager</span><span class="o">.</span><span class="na">isHeadlessSystemUserMode</span><span class="o">())</span> <span class="o">{</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="s">"startHomeOnAllDisplays"</span><span class="o">);</span>
<span class="n">mAtmInternal</span><span class="o">.</span><span class="na">startHomeOnAllDisplays</span><span class="o">(</span><span class="n">currentUserId</span><span class="o">,</span> <span class="s">"systemReady"</span><span class="o">);</span>
<span class="n">t</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>启动 Launcher 应用是在 <code class="language-plaintext highlighter-rouge">ActivityTaskManagerInternal#startHomeOnAllDisplays</code> 方法中,我们需要找一下 ActivityTaskManagerInternal 的实现类,但发现它是通过 <code class="language-plaintext highlighter-rouge">LocalServices.getService</code> 方法获取的:</p>
<blockquote>
<p><em>frameworks/base/core/java/com/android/server/LocalServices.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">LocalServices</span> <span class="o">{</span>
<span class="kd">private</span> <span class="nf">LocalServices</span><span class="o">()</span> <span class="o">{}</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">ArrayMap</span><span class="o"><</span><span class="nc">Class</span><span class="o"><?>,</span> <span class="nc">Object</span><span class="o">></span> <span class="n">sLocalServiceObjects</span> <span class="o">=</span>
<span class="k">new</span> <span class="nc">ArrayMap</span><span class="o"><</span><span class="nc">Class</span><span class="o"><?>,</span> <span class="nc">Object</span><span class="o">>();</span>
<span class="cm">/**
* Returns a local service instance that implements the specified interface.
*
* @param type The type of service.
* @return The service object.
*/</span>
<span class="nd">@SuppressWarnings</span><span class="o">(</span><span class="s">"unchecked"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="no">T</span> <span class="nf">getService</span><span class="o">(</span><span class="nc">Class</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">sLocalServiceObjects</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">(</span><span class="no">T</span><span class="o">)</span> <span class="n">sLocalServiceObjects</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Adds a service instance of the specified interface to the global registry of local services.
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="kt">void</span> <span class="nf">addService</span><span class="o">(</span><span class="nc">Class</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">type</span><span class="o">,</span> <span class="no">T</span> <span class="n">service</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">sLocalServiceObjects</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sLocalServiceObjects</span><span class="o">.</span><span class="na">containsKey</span><span class="o">(</span><span class="n">type</span><span class="o">))</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalStateException</span><span class="o">(</span><span class="s">"Overriding service registration"</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">sLocalServiceObjects</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">service</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Remove a service instance, must be only used in tests.
*/</span>
<span class="nd">@VisibleForTesting</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="kt">void</span> <span class="nf">removeServiceForTest</span><span class="o">(</span><span class="nc">Class</span><span class="o"><</span><span class="no">T</span><span class="o">></span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">sLocalServiceObjects</span><span class="o">)</span> <span class="o">{</span>
<span class="n">sLocalServiceObjects</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>不难发现,LocalServices 其实就是个容器类,用于存储各项服务,既然可以通过 getService 获取服务实现,那么添加服务应该就是通过 addService 实现的,我们查找一下调用该方法的地方,并指定 class 为 <code class="language-plaintext highlighter-rouge">ActivityTaskManagerInternal</code>,最终发现实现层在 <code class="language-plaintext highlighter-rouge">ActivityTaskManagerService#LocalService</code> 中:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ActivityTaskManagerService</span> <span class="kd">extends</span> <span class="nc">IActivityTaskManager</span><span class="o">.</span><span class="na">Stub</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nf">ActivityTaskManagerService</span><span class="o">(</span><span class="nc">Context</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mContext</span> <span class="o">=</span> <span class="n">context</span><span class="o">;</span>
<span class="o">...</span>
<span class="n">mInternal</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LocalService</span><span class="o">();</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">start</span><span class="o">()</span> <span class="o">{</span>
<span class="nc">LocalServices</span><span class="o">.</span><span class="na">addService</span><span class="o">(</span><span class="nc">ActivityTaskManagerInternal</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">mInternal</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="nc">LocalService</span> <span class="kd">extends</span> <span class="nc">ActivityTaskManagerInternal</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">startHomeOnAllDisplays</span><span class="o">(</span><span class="kt">int</span> <span class="n">userId</span><span class="o">,</span> <span class="nc">String</span> <span class="n">reason</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mGlobalLock</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">startHomeOnAllDisplays</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">reason</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>继续追溯到 <code class="language-plaintext highlighter-rouge">WindowManagerService#mRoot</code> 并查找实现:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre> <span class="kt">boolean</span> <span class="nf">startHomeOnDisplay</span><span class="o">(</span><span class="kt">int</span> <span class="n">userId</span><span class="o">,</span> <span class="nc">String</span> <span class="n">reason</span><span class="o">,</span> <span class="kt">int</span> <span class="n">displayId</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">allowInstrumenting</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">fromHomeKey</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Fallback to top focused display or default display if the displayId is invalid.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">displayId</span> <span class="o">==</span> <span class="no">INVALID_DISPLAY</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">rootTask</span> <span class="o">=</span> <span class="n">getTopDisplayFocusedRootTask</span><span class="o">();</span>
<span class="n">displayId</span> <span class="o">=</span> <span class="n">rootTask</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">rootTask</span><span class="o">.</span><span class="na">getDisplayId</span><span class="o">()</span> <span class="o">:</span> <span class="no">DEFAULT_DISPLAY</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="nc">DisplayContent</span> <span class="n">display</span> <span class="o">=</span> <span class="n">getDisplayContent</span><span class="o">(</span><span class="n">displayId</span><span class="o">);</span>
<span class="k">return</span> <span class="n">display</span><span class="o">.</span><span class="na">reduceOnAllTaskDisplayAreas</span><span class="o">((</span><span class="n">taskDisplayArea</span><span class="o">,</span> <span class="n">result</span><span class="o">)</span> <span class="o">-></span>
<span class="n">result</span> <span class="o">|</span> <span class="n">startHomeOnTaskDisplayArea</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">reason</span><span class="o">,</span> <span class="n">taskDisplayArea</span><span class="o">,</span>
<span class="n">allowInstrumenting</span><span class="o">,</span> <span class="n">fromHomeKey</span><span class="o">),</span>
<span class="kc">false</span> <span class="cm">/* initValue */</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>继续再跟进到该类的 <code class="language-plaintext highlighter-rouge">startHomeOnTaskDisplayArea</code> 中:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* This starts home activity on display areas that can have system decorations based on
* displayId - default display area always uses primary home component.
* For secondary display areas, the home activity must have category SECONDARY_HOME and then
* resolves according to the priorities listed below.
* - If default home is not set, always use the secondary home defined in the config.
* - Use currently selected primary home activity.
* - Use the activity in the same package as currently selected primary home activity.
* If there are multiple activities matched, use first one.
* - Use the secondary home defined in the config.
*/</span>
<span class="kt">boolean</span> <span class="nf">startHomeOnTaskDisplayArea</span><span class="o">(</span><span class="kt">int</span> <span class="n">userId</span><span class="o">,</span> <span class="nc">String</span> <span class="n">reason</span><span class="o">,</span> <span class="nc">TaskDisplayArea</span> <span class="n">taskDisplayArea</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">allowInstrumenting</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">fromHomeKey</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Fallback to top focused display area if the provided one is invalid.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">taskDisplayArea</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">rootTask</span> <span class="o">=</span> <span class="n">getTopDisplayFocusedRootTask</span><span class="o">();</span>
<span class="n">taskDisplayArea</span> <span class="o">=</span> <span class="n">rootTask</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">rootTask</span><span class="o">.</span><span class="na">getDisplayArea</span><span class="o">()</span>
<span class="o">:</span> <span class="n">getDefaultTaskDisplayArea</span><span class="o">();</span>
<span class="o">}</span>
<span class="nc">Intent</span> <span class="n">homeIntent</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">ActivityInfo</span> <span class="n">aInfo</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">taskDisplayArea</span> <span class="o">==</span> <span class="n">getDefaultTaskDisplayArea</span><span class="o">())</span> <span class="o">{</span>
<span class="n">homeIntent</span> <span class="o">=</span> <span class="n">mService</span><span class="o">.</span><span class="na">getHomeIntent</span><span class="o">();</span>
<span class="n">aInfo</span> <span class="o">=</span> <span class="n">resolveHomeActivity</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">homeIntent</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">shouldPlaceSecondaryHomeOnDisplayArea</span><span class="o">(</span><span class="n">taskDisplayArea</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Pair</span><span class="o"><</span><span class="nc">ActivityInfo</span><span class="o">,</span> <span class="nc">Intent</span><span class="o">></span> <span class="n">info</span> <span class="o">=</span> <span class="n">resolveSecondaryHomeActivity</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">taskDisplayArea</span><span class="o">);</span>
<span class="n">aInfo</span> <span class="o">=</span> <span class="n">info</span><span class="o">.</span><span class="na">first</span><span class="o">;</span>
<span class="n">homeIntent</span> <span class="o">=</span> <span class="n">info</span><span class="o">.</span><span class="na">second</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">aInfo</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">homeIntent</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">canStartHomeOnDisplayArea</span><span class="o">(</span><span class="n">aInfo</span><span class="o">,</span> <span class="n">taskDisplayArea</span><span class="o">,</span> <span class="n">allowInstrumenting</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// Updates the home component of the intent.</span>
<span class="n">homeIntent</span><span class="o">.</span><span class="na">setComponent</span><span class="o">(</span><span class="k">new</span> <span class="nc">ComponentName</span><span class="o">(</span><span class="n">aInfo</span><span class="o">.</span><span class="na">applicationInfo</span><span class="o">.</span><span class="na">packageName</span><span class="o">,</span> <span class="n">aInfo</span><span class="o">.</span><span class="na">name</span><span class="o">));</span>
<span class="n">homeIntent</span><span class="o">.</span><span class="na">setFlags</span><span class="o">(</span><span class="n">homeIntent</span><span class="o">.</span><span class="na">getFlags</span><span class="o">()</span> <span class="o">|</span> <span class="no">FLAG_ACTIVITY_NEW_TASK</span><span class="o">);</span>
<span class="c1">// Updates the extra information of the intent.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">fromHomeKey</span><span class="o">)</span> <span class="o">{</span>
<span class="n">homeIntent</span><span class="o">.</span><span class="na">putExtra</span><span class="o">(</span><span class="nc">WindowManagerPolicy</span><span class="o">.</span><span class="na">EXTRA_FROM_HOME_KEY</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mWindowManager</span><span class="o">.</span><span class="na">getRecentsAnimationController</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mWindowManager</span><span class="o">.</span><span class="na">getRecentsAnimationController</span><span class="o">().</span><span class="na">cancelAnimationForHomeStart</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">homeIntent</span><span class="o">.</span><span class="na">putExtra</span><span class="o">(</span><span class="nc">WindowManagerPolicy</span><span class="o">.</span><span class="na">EXTRA_START_REASON</span><span class="o">,</span> <span class="n">reason</span><span class="o">);</span>
<span class="c1">// Update the reason for ANR debugging to verify if the user activity is the one that</span>
<span class="c1">// actually launched.</span>
<span class="kd">final</span> <span class="nc">String</span> <span class="n">myReason</span> <span class="o">=</span> <span class="n">reason</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="n">userId</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="nc">UserHandle</span><span class="o">.</span><span class="na">getUserId</span><span class="o">(</span>
<span class="n">aInfo</span><span class="o">.</span><span class="na">applicationInfo</span><span class="o">.</span><span class="na">uid</span><span class="o">)</span> <span class="o">+</span> <span class="s">":"</span> <span class="o">+</span> <span class="n">taskDisplayArea</span><span class="o">.</span><span class="na">getDisplayId</span><span class="o">();</span>
<span class="n">mService</span><span class="o">.</span><span class="na">getActivityStartController</span><span class="o">().</span><span class="na">startHomeActivity</span><span class="o">(</span><span class="n">homeIntent</span><span class="o">,</span> <span class="n">aInfo</span><span class="o">,</span> <span class="n">myReason</span><span class="o">,</span>
<span class="n">taskDisplayArea</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>定位到这里就知道我们离最终启动 Launcher 进程的地方不远了,因为我们发现了 Intent 的踪迹,这个方法内构建了一个 <code class="language-plaintext highlighter-rouge">homeIntent</code> 用于启动 Launcher 的 Activity。于是继续跟进:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityStartController.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">startHomeActivity</span><span class="o">(</span><span class="nc">Intent</span> <span class="n">intent</span><span class="o">,</span> <span class="nc">ActivityInfo</span> <span class="n">aInfo</span><span class="o">,</span> <span class="nc">String</span> <span class="n">reason</span><span class="o">,</span>
<span class="nc">TaskDisplayArea</span> <span class="n">taskDisplayArea</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">ActivityOptions</span> <span class="n">options</span> <span class="o">=</span> <span class="nc">ActivityOptions</span><span class="o">.</span><span class="na">makeBasic</span><span class="o">();</span>
<span class="n">options</span><span class="o">.</span><span class="na">setLaunchWindowingMode</span><span class="o">(</span><span class="no">WINDOWING_MODE_FULLSCREEN</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(!</span><span class="nc">ActivityRecord</span><span class="o">.</span><span class="na">isResolverActivity</span><span class="o">(</span><span class="n">aInfo</span><span class="o">.</span><span class="na">name</span><span class="o">))</span> <span class="o">{</span>
<span class="c1">// The resolver activity shouldn't be put in root home task because when the</span>
<span class="c1">// foreground is standard type activity, the resolver activity should be put on the</span>
<span class="c1">// top of current foreground instead of bring root home task to front.</span>
<span class="n">options</span><span class="o">.</span><span class="na">setLaunchActivityType</span><span class="o">(</span><span class="no">ACTIVITY_TYPE_HOME</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">displayId</span> <span class="o">=</span> <span class="n">taskDisplayArea</span><span class="o">.</span><span class="na">getDisplayId</span><span class="o">();</span>
<span class="n">options</span><span class="o">.</span><span class="na">setLaunchDisplayId</span><span class="o">(</span><span class="n">displayId</span><span class="o">);</span>
<span class="n">options</span><span class="o">.</span><span class="na">setLaunchTaskDisplayArea</span><span class="o">(</span><span class="n">taskDisplayArea</span><span class="o">.</span><span class="na">mRemoteToken</span>
<span class="o">.</span><span class="na">toWindowContainerToken</span><span class="o">());</span>
<span class="c1">// The home activity will be started later, defer resuming to avoid unnecessary operations</span>
<span class="c1">// (e.g. start home recursively) when creating root home task.</span>
<span class="n">mSupervisor</span><span class="o">.</span><span class="na">beginDeferResume</span><span class="o">();</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">rootHomeTask</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// Make sure root home task exists on display area.</span>
<span class="n">rootHomeTask</span> <span class="o">=</span> <span class="n">taskDisplayArea</span><span class="o">.</span><span class="na">getOrCreateRootHomeTask</span><span class="o">(</span><span class="no">ON_TOP</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mSupervisor</span><span class="o">.</span><span class="na">endDeferResume</span><span class="o">();</span>
<span class="o">}</span>
<span class="n">mLastHomeActivityStartResult</span> <span class="o">=</span> <span class="n">obtainStarter</span><span class="o">(</span><span class="n">intent</span><span class="o">,</span> <span class="s">"startHomeActivity: "</span> <span class="o">+</span> <span class="n">reason</span><span class="o">)</span>
<span class="o">.</span><span class="na">setOutActivity</span><span class="o">(</span><span class="n">tmpOutRecord</span><span class="o">)</span>
<span class="o">.</span><span class="na">setCallingUid</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span>
<span class="o">.</span><span class="na">setActivityInfo</span><span class="o">(</span><span class="n">aInfo</span><span class="o">)</span>
<span class="o">.</span><span class="na">setActivityOptions</span><span class="o">(</span><span class="n">options</span><span class="o">.</span><span class="na">toBundle</span><span class="o">())</span>
<span class="o">.</span><span class="na">execute</span><span class="o">();</span>
<span class="n">mLastHomeActivityStartRecord</span> <span class="o">=</span> <span class="n">tmpOutRecord</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rootHomeTask</span><span class="o">.</span><span class="na">mInResumeTopActivity</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// If we are in resume section already, home activity will be initialized, but not</span>
<span class="c1">// resumed (to avoid recursive resume) and will stay that way until something pokes it</span>
<span class="c1">// again. We need to schedule another resume.</span>
<span class="n">mSupervisor</span><span class="o">.</span><span class="na">scheduleResumeTopActivities</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>接着发现启动 Launcher 是通过 obtainStarter 获取 ActivityStarter 并内部调用 execute 方法来实现的,而这里的 mLastHomeActivityStartResult 则是启动结果。我们具体来看下 ActivityStarter 的 execute 是如何实现的:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/</span>
<span class="kt">int</span> <span class="nf">execute</span><span class="o">()</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">onExecutionStarted</span><span class="o">();</span>
<span class="c1">// Refuse possible leaked file descriptors</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">intent</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">intent</span><span class="o">.</span><span class="na">hasFileDescriptors</span><span class="o">())</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"File descriptors passed in Intent"</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="nc">LaunchingState</span> <span class="n">launchingState</span><span class="o">;</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mService</span><span class="o">.</span><span class="na">mGlobalLock</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">caller</span> <span class="o">=</span> <span class="nc">ActivityRecord</span><span class="o">.</span><span class="na">forTokenLocked</span><span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">resultTo</span><span class="o">);</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">callingUid</span> <span class="o">=</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">realCallingUid</span> <span class="o">==</span> <span class="nc">Request</span><span class="o">.</span><span class="na">DEFAULT_REAL_CALLING_UID</span>
<span class="o">?</span> <span class="nc">Binder</span><span class="o">.</span><span class="na">getCallingUid</span><span class="o">()</span> <span class="o">:</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">realCallingUid</span><span class="o">;</span>
<span class="n">launchingState</span> <span class="o">=</span> <span class="n">mSupervisor</span><span class="o">.</span><span class="na">getActivityMetricsLogger</span><span class="o">().</span><span class="na">notifyActivityLaunching</span><span class="o">(</span>
<span class="n">mRequest</span><span class="o">.</span><span class="na">intent</span><span class="o">,</span> <span class="n">caller</span><span class="o">,</span> <span class="n">callingUid</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// If the caller hasn't already resolved the activity, we're willing</span>
<span class="c1">// to do so here. If the caller is already holding the WM lock here,</span>
<span class="c1">// and we need to check dynamic Uri permissions, then we're forced</span>
<span class="c1">// to assume those permissions are denied to avoid deadlocking.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">activityInfo</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mRequest</span><span class="o">.</span><span class="na">resolveActivity</span><span class="o">(</span><span class="n">mSupervisor</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Add checkpoint for this shutdown or reboot attempt, so we can record the original</span>
<span class="c1">// intent action and package name.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">intent</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">String</span> <span class="n">intentAction</span> <span class="o">=</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">intent</span><span class="o">.</span><span class="na">getAction</span><span class="o">();</span>
<span class="nc">String</span> <span class="n">callingPackage</span> <span class="o">=</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">callingPackage</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">intentAction</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">callingPackage</span> <span class="o">!=</span> <span class="kc">null</span>
<span class="o">&&</span> <span class="o">(</span><span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_REQUEST_SHUTDOWN</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">intentAction</span><span class="o">)</span>
<span class="o">||</span> <span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_SHUTDOWN</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">intentAction</span><span class="o">)</span>
<span class="o">||</span> <span class="nc">Intent</span><span class="o">.</span><span class="na">ACTION_REBOOT</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">intentAction</span><span class="o">)))</span> <span class="o">{</span>
<span class="nc">ShutdownCheckPoints</span><span class="o">.</span><span class="na">recordCheckPoint</span><span class="o">(</span><span class="n">intentAction</span><span class="o">,</span> <span class="n">callingPackage</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="n">res</span><span class="o">;</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mService</span><span class="o">.</span><span class="na">mGlobalLock</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">globalConfigWillChange</span> <span class="o">=</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">globalConfig</span> <span class="o">!=</span> <span class="kc">null</span>
<span class="o">&&</span> <span class="n">mService</span><span class="o">.</span><span class="na">getGlobalConfiguration</span><span class="o">().</span><span class="na">diff</span><span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">globalConfig</span><span class="o">)</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">rootTask</span> <span class="o">=</span> <span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">getTopDisplayFocusedRootTask</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rootTask</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">rootTask</span><span class="o">.</span><span class="na">mConfigWillChange</span> <span class="o">=</span> <span class="n">globalConfigWillChange</span><span class="o">;</span>
<span class="o">}</span>
<span class="nc">ProtoLog</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">WM_DEBUG_CONFIGURATION</span><span class="o">,</span> <span class="s">"Starting activity when config "</span>
<span class="o">+</span> <span class="s">"will change = %b"</span><span class="o">,</span> <span class="n">globalConfigWillChange</span><span class="o">);</span>
<span class="kd">final</span> <span class="kt">long</span> <span class="n">origId</span> <span class="o">=</span> <span class="nc">Binder</span><span class="o">.</span><span class="na">clearCallingIdentity</span><span class="o">();</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">resolveToHeavyWeightSwitcherIfNeeded</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">res</span> <span class="o">!=</span> <span class="no">START_SUCCESS</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">res</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">executeRequest</span><span class="o">(</span><span class="n">mRequest</span><span class="o">);</span>
<span class="nc">Binder</span><span class="o">.</span><span class="na">restoreCallingIdentity</span><span class="o">(</span><span class="n">origId</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">globalConfigWillChange</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// If the caller also wants to switch to a new configuration, do so now.</span>
<span class="c1">// This allows a clean switch, as we are waiting for the current activity</span>
<span class="c1">// to pause (so we will not destroy it), and have not yet started the</span>
<span class="c1">// next activity.</span>
<span class="n">mService</span><span class="o">.</span><span class="na">mAmInternal</span><span class="o">.</span><span class="na">enforceCallingPermission</span><span class="o">(</span>
<span class="n">android</span><span class="o">.</span><span class="na">Manifest</span><span class="o">.</span><span class="na">permission</span><span class="o">.</span><span class="na">CHANGE_CONFIGURATION</span><span class="o">,</span>
<span class="s">"updateConfiguration()"</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rootTask</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">rootTask</span><span class="o">.</span><span class="na">mConfigWillChange</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="nc">ProtoLog</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">WM_DEBUG_CONFIGURATION</span><span class="o">,</span>
<span class="s">"Updating to new configuration after starting activity."</span><span class="o">);</span>
<span class="n">mService</span><span class="o">.</span><span class="na">updateConfigurationLocked</span><span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">globalConfig</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// The original options may have additional info about metrics. The mOptions is not</span>
<span class="c1">// used here because it may be cleared in setTargetRootTaskIfNeeded.</span>
<span class="kd">final</span> <span class="nc">ActivityOptions</span> <span class="n">originalOptions</span> <span class="o">=</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">activityOptions</span> <span class="o">!=</span> <span class="kc">null</span>
<span class="o">?</span> <span class="n">mRequest</span><span class="o">.</span><span class="na">activityOptions</span><span class="o">.</span><span class="na">getOriginalOptions</span><span class="o">()</span> <span class="o">:</span> <span class="kc">null</span><span class="o">;</span>
<span class="c1">// If the new record is the one that started, a new activity has created.</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">newActivityCreated</span> <span class="o">=</span> <span class="n">mStartActivity</span> <span class="o">==</span> <span class="n">mLastStartActivityRecord</span><span class="o">;</span>
<span class="c1">// Notify ActivityMetricsLogger that the activity has launched.</span>
<span class="c1">// ActivityMetricsLogger will then wait for the windows to be drawn and populate</span>
<span class="c1">// WaitResult.</span>
<span class="n">mSupervisor</span><span class="o">.</span><span class="na">getActivityMetricsLogger</span><span class="o">().</span><span class="na">notifyActivityLaunched</span><span class="o">(</span><span class="n">launchingState</span><span class="o">,</span> <span class="n">res</span><span class="o">,</span>
<span class="n">newActivityCreated</span><span class="o">,</span> <span class="n">mLastStartActivityRecord</span><span class="o">,</span> <span class="n">originalOptions</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">waitResult</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mRequest</span><span class="o">.</span><span class="na">waitResult</span><span class="o">.</span><span class="na">result</span> <span class="o">=</span> <span class="n">res</span><span class="o">;</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">waitResultIfNeeded</span><span class="o">(</span><span class="n">mRequest</span><span class="o">.</span><span class="na">waitResult</span><span class="o">,</span> <span class="n">mLastStartActivityRecord</span><span class="o">,</span>
<span class="n">launchingState</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="nf">getExternalResult</span><span class="o">(</span><span class="n">res</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">onExecutionComplete</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>这里主要做一些 Activity 启动相关细节参数的校验,验证通过后继续执行 <code class="language-plaintext highlighter-rouge">executeRequest</code> 方法:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
</pre></td><td class="rouge-code"><pre> <span class="cm">/**
* Executing activity start request and starts the journey of starting an activity. Here
* begins with performing several preliminary checks. The normally activity launch flow will
* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
*/</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="nf">executeRequest</span><span class="o">(</span><span class="nc">Request</span> <span class="n">request</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">r</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ActivityRecord</span><span class="o">.</span><span class="na">Builder</span><span class="o">(</span><span class="n">mService</span><span class="o">)</span>
<span class="o">.</span><span class="na">setCaller</span><span class="o">(</span><span class="n">callerApp</span><span class="o">)</span>
<span class="o">.</span><span class="na">setLaunchedFromPid</span><span class="o">(</span><span class="n">callingPid</span><span class="o">)</span>
<span class="o">.</span><span class="na">setLaunchedFromUid</span><span class="o">(</span><span class="n">callingUid</span><span class="o">)</span>
<span class="o">.</span><span class="na">setLaunchedFromPackage</span><span class="o">(</span><span class="n">callingPackage</span><span class="o">)</span>
<span class="o">.</span><span class="na">setLaunchedFromFeature</span><span class="o">(</span><span class="n">callingFeatureId</span><span class="o">)</span>
<span class="o">.</span><span class="na">setIntent</span><span class="o">(</span><span class="n">intent</span><span class="o">)</span>
<span class="o">.</span><span class="na">setResolvedType</span><span class="o">(</span><span class="n">resolvedType</span><span class="o">)</span>
<span class="o">.</span><span class="na">setActivityInfo</span><span class="o">(</span><span class="n">aInfo</span><span class="o">)</span>
<span class="o">.</span><span class="na">setConfiguration</span><span class="o">(</span><span class="n">mService</span><span class="o">.</span><span class="na">getGlobalConfiguration</span><span class="o">())</span>
<span class="o">.</span><span class="na">setResultTo</span><span class="o">(</span><span class="n">resultRecord</span><span class="o">)</span>
<span class="o">.</span><span class="na">setResultWho</span><span class="o">(</span><span class="n">resultWho</span><span class="o">)</span>
<span class="o">.</span><span class="na">setRequestCode</span><span class="o">(</span><span class="n">requestCode</span><span class="o">)</span>
<span class="o">.</span><span class="na">setComponentSpecified</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">componentSpecified</span><span class="o">)</span>
<span class="o">.</span><span class="na">setRootVoiceInteraction</span><span class="o">(</span><span class="n">voiceSession</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
<span class="o">.</span><span class="na">setActivityOptions</span><span class="o">(</span><span class="n">checkedOptions</span><span class="o">)</span>
<span class="o">.</span><span class="na">setSourceRecord</span><span class="o">(</span><span class="n">sourceRecord</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="n">mLastStartActivityRecord</span> <span class="o">=</span> <span class="n">r</span><span class="o">;</span>
<span class="o">...</span>
<span class="n">mLastStartActivityResult</span> <span class="o">=</span> <span class="n">startActivityUnchecked</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">sourceRecord</span><span class="o">,</span> <span class="n">voiceSession</span><span class="o">,</span>
<span class="n">request</span><span class="o">.</span><span class="na">voiceInteractor</span><span class="o">,</span> <span class="n">startFlags</span><span class="o">,</span> <span class="kc">true</span> <span class="cm">/* doResume */</span><span class="o">,</span> <span class="n">checkedOptions</span><span class="o">,</span>
<span class="n">inTask</span><span class="o">,</span> <span class="n">inTaskFragment</span><span class="o">,</span> <span class="n">restrictedBgActivity</span><span class="o">,</span> <span class="n">intentGrants</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">outActivity</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">request</span><span class="o">.</span><span class="na">outActivity</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="n">mLastStartActivityRecord</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">mLastStartActivityResult</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>首先构建了一个 ActivityRecord 用于记录 Activity 相关信息(如包名、进程名、启动模式、task 信息等),接着调用 <code class="language-plaintext highlighter-rouge">startActivityUnchecked</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Start an activity while most of preliminary checks has been done and caller has been
* confirmed that holds necessary permissions to do so.
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="nf">startActivityUnchecked</span><span class="o">(</span><span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">,</span> <span class="nc">ActivityRecord</span> <span class="n">sourceRecord</span><span class="o">,</span>
<span class="nc">IVoiceInteractionSession</span> <span class="n">voiceSession</span><span class="o">,</span> <span class="nc">IVoiceInteractor</span> <span class="n">voiceInteractor</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">startFlags</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">doResume</span><span class="o">,</span> <span class="nc">ActivityOptions</span> <span class="n">options</span><span class="o">,</span> <span class="nc">Task</span> <span class="n">inTask</span><span class="o">,</span>
<span class="nc">TaskFragment</span> <span class="n">inTaskFragment</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">restrictedBgActivity</span><span class="o">,</span>
<span class="nc">NeededUriGrants</span> <span class="n">intentGrants</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="no">START_CANCELED</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">startedActivityRootTask</span><span class="o">;</span>
<span class="c1">// Create a transition now to record the original intent of actions taken within</span>
<span class="c1">// startActivityInner. Otherwise, logic in startActivityInner could start a different</span>
<span class="c1">// transition based on a sub-action.</span>
<span class="c1">// Only do the create here (and defer requestStart) since startActivityInner might abort.</span>
<span class="kd">final</span> <span class="nc">TransitionController</span> <span class="n">transitionController</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="na">mTransitionController</span><span class="o">;</span>
<span class="nc">Transition</span> <span class="n">newTransition</span> <span class="o">=</span> <span class="o">(!</span><span class="n">transitionController</span><span class="o">.</span><span class="na">isCollecting</span><span class="o">()</span>
<span class="o">&&</span> <span class="n">transitionController</span><span class="o">.</span><span class="na">getTransitionPlayer</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span>
<span class="o">?</span> <span class="n">transitionController</span><span class="o">.</span><span class="na">createTransition</span><span class="o">(</span><span class="no">TRANSIT_OPEN</span><span class="o">)</span> <span class="o">:</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">RemoteTransition</span> <span class="n">remoteTransition</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="na">takeRemoteTransition</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mService</span><span class="o">.</span><span class="na">deferWindowLayout</span><span class="o">();</span>
<span class="n">transitionController</span><span class="o">.</span><span class="na">collect</span><span class="o">(</span><span class="n">r</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_WINDOW_MANAGER</span><span class="o">,</span> <span class="s">"startActivityInner"</span><span class="o">);</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">startActivityInner</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">sourceRecord</span><span class="o">,</span> <span class="n">voiceSession</span><span class="o">,</span> <span class="n">voiceInteractor</span><span class="o">,</span>
<span class="n">startFlags</span><span class="o">,</span> <span class="n">doResume</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span> <span class="n">inTask</span><span class="o">,</span> <span class="n">inTaskFragment</span><span class="o">,</span> <span class="n">restrictedBgActivity</span><span class="o">,</span>
<span class="n">intentGrants</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_WINDOW_MANAGER</span><span class="o">);</span>
<span class="n">startedActivityRootTask</span> <span class="o">=</span> <span class="n">handleStartResult</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span> <span class="n">result</span><span class="o">,</span> <span class="n">newTransition</span><span class="o">,</span>
<span class="n">remoteTransition</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mService</span><span class="o">.</span><span class="na">continueWindowLayout</span><span class="o">();</span>
<span class="o">}</span>
<span class="n">postStartActivityProcessing</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">result</span><span class="o">,</span> <span class="n">startedActivityRootTask</span><span class="o">);</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>继续追踪到 <code class="language-plaintext highlighter-rouge">startActivityInner</code> 方法中:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
</pre></td><td class="rouge-code"><pre><span class="kt">int</span> <span class="nf">startActivityInner</span><span class="o">(</span><span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">,</span> <span class="nc">ActivityRecord</span> <span class="n">sourceRecord</span><span class="o">,</span>
<span class="nc">IVoiceInteractionSession</span> <span class="n">voiceSession</span><span class="o">,</span> <span class="nc">IVoiceInteractor</span> <span class="n">voiceInteractor</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">startFlags</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">doResume</span><span class="o">,</span> <span class="nc">ActivityOptions</span> <span class="n">options</span><span class="o">,</span> <span class="nc">Task</span> <span class="n">inTask</span><span class="o">,</span>
<span class="nc">TaskFragment</span> <span class="n">inTaskFragment</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">restrictedBgActivity</span><span class="o">,</span>
<span class="nc">NeededUriGrants</span> <span class="n">intentGrants</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mDoResume</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">topTaskActivity</span> <span class="o">=</span> <span class="n">startedTask</span><span class="o">.</span><span class="na">topRunningActivityLocked</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">mTargetRootTask</span><span class="o">.</span><span class="na">isTopActivityFocusable</span><span class="o">()</span>
<span class="o">||</span> <span class="o">(</span><span class="n">topTaskActivity</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">topTaskActivity</span><span class="o">.</span><span class="na">isTaskOverlay</span><span class="o">()</span>
<span class="o">&&</span> <span class="n">mStartActivity</span> <span class="o">!=</span> <span class="n">topTaskActivity</span><span class="o">))</span> <span class="o">{</span>
<span class="n">mTargetRootTask</span><span class="o">.</span><span class="na">ensureActivitiesVisible</span><span class="o">(</span><span class="kc">null</span> <span class="cm">/* starting */</span><span class="o">,</span>
<span class="mi">0</span> <span class="cm">/* configChanges */</span><span class="o">,</span> <span class="o">!</span><span class="no">PRESERVE_WINDOWS</span><span class="o">);</span>
<span class="n">mTargetRootTask</span><span class="o">.</span><span class="na">mDisplayContent</span><span class="o">.</span><span class="na">executeAppTransition</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// If the target root-task was not previously focusable (previous top running</span>
<span class="c1">// activity on that root-task was not visible) then any prior calls to move the</span>
<span class="c1">// root-task to the will not update the focused root-task. If starting the new</span>
<span class="c1">// activity now allows the task root-task to be focusable, then ensure that we</span>
<span class="c1">// now update the focused root-task accordingly.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mTargetRootTask</span><span class="o">.</span><span class="na">isTopActivityFocusable</span><span class="o">()</span>
<span class="o">&&</span> <span class="o">!</span><span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">isTopDisplayFocusedRootTask</span><span class="o">(</span><span class="n">mTargetRootTask</span><span class="o">))</span> <span class="o">{</span>
<span class="n">mTargetRootTask</span><span class="o">.</span><span class="na">moveToFront</span><span class="o">(</span><span class="s">"startActivityInner"</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">resumeFocusedTasksTopActivities</span><span class="o">(</span>
<span class="n">mTargetRootTask</span><span class="o">,</span> <span class="n">mStartActivity</span><span class="o">,</span> <span class="n">mOptions</span><span class="o">,</span> <span class="n">mTransientLaunch</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">updateUserRootTask</span><span class="o">(</span><span class="n">mStartActivity</span><span class="o">.</span><span class="na">mUserId</span><span class="o">,</span> <span class="n">mTargetRootTask</span><span class="o">);</span>
<span class="o">...</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>发现最终又调用回了 RootWindowContainer:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
</pre></td><td class="rouge-code"><pre><span class="kt">boolean</span> <span class="nf">resumeFocusedTasksTopActivities</span><span class="o">(</span>
<span class="nc">Task</span> <span class="n">targetRootTask</span><span class="o">,</span> <span class="nc">ActivityRecord</span> <span class="n">target</span><span class="o">,</span> <span class="nc">ActivityOptions</span> <span class="n">targetOptions</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">deferPause</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">readyToResume</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="n">result</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="c1">// 如果是栈顶 Activity 则调用 resumeTopActivityUncheckedLocked</span>
<span class="k">if</span> <span class="o">(</span><span class="n">targetRootTask</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">(</span><span class="n">targetRootTask</span><span class="o">.</span><span class="na">isTopRootTaskInDisplayArea</span><span class="o">()</span>
<span class="o">||</span> <span class="n">getTopDisplayFocusedRootTask</span><span class="o">()</span> <span class="o">==</span> <span class="n">targetRootTask</span><span class="o">))</span> <span class="o">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">targetRootTask</span><span class="o">.</span><span class="na">resumeTopActivityUncheckedLocked</span><span class="o">(</span><span class="n">target</span><span class="o">,</span> <span class="n">targetOptions</span><span class="o">,</span>
<span class="n">deferPause</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">displayNdx</span> <span class="o">=</span> <span class="n">getChildCount</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">displayNdx</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">displayNdx</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">DisplayContent</span> <span class="n">display</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">displayNdx</span><span class="o">);</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">curResult</span> <span class="o">=</span> <span class="n">result</span><span class="o">;</span>
<span class="kt">boolean</span><span class="o">[]</span> <span class="n">resumedOnDisplay</span> <span class="o">=</span> <span class="k">new</span> <span class="kt">boolean</span><span class="o">[</span><span class="mi">1</span><span class="o">];</span>
<span class="n">display</span><span class="o">.</span><span class="na">forAllRootTasks</span><span class="o">(</span><span class="n">rootTask</span> <span class="o">-></span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">topRunningActivity</span> <span class="o">=</span> <span class="n">rootTask</span><span class="o">.</span><span class="na">topRunningActivity</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">rootTask</span><span class="o">.</span><span class="na">isFocusableAndVisible</span><span class="o">()</span> <span class="o">||</span> <span class="n">topRunningActivity</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rootTask</span> <span class="o">==</span> <span class="n">targetRootTask</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Simply update the result for targetRootTask because the targetRootTask</span>
<span class="c1">// had already resumed in above. We don't want to resume it again,</span>
<span class="c1">// especially in some cases, it would cause a second launch failure</span>
<span class="c1">// if app process was dead.</span>
<span class="n">resumedOnDisplay</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">|=</span> <span class="n">curResult</span><span class="o">;</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rootTask</span><span class="o">.</span><span class="na">getDisplayArea</span><span class="o">().</span><span class="na">isTopRootTask</span><span class="o">(</span><span class="n">rootTask</span><span class="o">)</span>
<span class="o">&&</span> <span class="n">topRunningActivity</span><span class="o">.</span><span class="na">isState</span><span class="o">(</span><span class="no">RESUMED</span><span class="o">))</span> <span class="o">{</span>
<span class="c1">// Kick off any lingering app transitions from the MoveTaskToFront</span>
<span class="c1">// operation, but only consider the top task and root-task on that</span>
<span class="c1">// display.</span>
<span class="n">rootTask</span><span class="o">.</span><span class="na">executeAppTransition</span><span class="o">(</span><span class="n">targetOptions</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">resumedOnDisplay</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">|=</span> <span class="n">topRunningActivity</span><span class="o">.</span><span class="na">makeActiveIfNeeded</span><span class="o">(</span><span class="n">target</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="n">result</span> <span class="o">|=</span> <span class="n">resumedOnDisplay</span><span class="o">[</span><span class="mi">0</span><span class="o">];</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">resumedOnDisplay</span><span class="o">[</span><span class="mi">0</span><span class="o">])</span> <span class="o">{</span>
<span class="c1">// In cases when there are no valid activities (e.g. device just booted or launcher</span>
<span class="c1">// crashed) it's possible that nothing was resumed on a display. Requesting resume</span>
<span class="c1">// of top activity in focused root task explicitly will make sure that at least home</span>
<span class="c1">// activity is started and resumed, and no recursion occurs.</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">focusedRoot</span> <span class="o">=</span> <span class="n">display</span><span class="o">.</span><span class="na">getFocusedRootTask</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">focusedRoot</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">result</span> <span class="o">|=</span> <span class="n">focusedRoot</span><span class="o">.</span><span class="na">resumeTopActivityUncheckedLocked</span><span class="o">(</span><span class="n">target</span><span class="o">,</span> <span class="n">targetOptions</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">targetRootTask</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">result</span> <span class="o">|=</span> <span class="n">resumeHomeActivity</span><span class="o">(</span><span class="kc">null</span> <span class="cm">/* prev */</span><span class="o">,</span> <span class="s">"no-focusable-task"</span><span class="o">,</span>
<span class="n">display</span><span class="o">.</span><span class="na">getDefaultTaskDisplayArea</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>第一次正常启动 Launcher 会执行到 <code class="language-plaintext highlighter-rouge">resumeTopActivityUncheckedLocked</code>:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/Task.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Ensure that the top activity in the root task is resumed.
*
* @param prev The previously resumed activity, for when in the process
* of pausing; can be null to call from elsewhere.
* @param options Activity options.
* @param deferPause When {@code true}, this will not pause back tasks.
*
* @return Returns true if something is being resumed, or false if
* nothing happened.
*
* NOTE: It is not safe to call this method directly as it can cause an activity in a
* non-focused root task to be resumed.
* Use {@link RootWindowContainer#resumeFocusedTasksTopActivities} to resume the
* right activity for the current system state.
*/</span>
<span class="nd">@GuardedBy</span><span class="o">(</span><span class="s">"mService"</span><span class="o">)</span>
<span class="kt">boolean</span> <span class="nf">resumeTopActivityUncheckedLocked</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">prev</span><span class="o">,</span> <span class="nc">ActivityOptions</span> <span class="n">options</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">deferPause</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mInResumeTopActivity</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Don't even start recursing.</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="n">someActivityResumed</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// Protect against recursion.</span>
<span class="n">mInResumeTopActivity</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">isLeafTask</span><span class="o">())</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">isFocusableAndVisible</span><span class="o">())</span> <span class="o">{</span>
<span class="n">someActivityResumed</span> <span class="o">=</span> <span class="n">resumeTopActivityInnerLocked</span><span class="o">(</span><span class="n">prev</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span> <span class="n">deferPause</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">idx</span> <span class="o">=</span> <span class="n">mChildren</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
<span class="k">while</span> <span class="o">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Task</span> <span class="n">child</span> <span class="o">=</span> <span class="o">(</span><span class="nc">Task</span><span class="o">)</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">idx</span><span class="o">--);</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">child</span><span class="o">.</span><span class="na">isTopActivityFocusable</span><span class="o">())</span> <span class="o">{</span>
<span class="k">continue</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">child</span><span class="o">.</span><span class="na">getVisibility</span><span class="o">(</span><span class="kc">null</span> <span class="cm">/* starting */</span><span class="o">)</span>
<span class="o">!=</span> <span class="no">TASK_FRAGMENT_VISIBILITY_VISIBLE</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">child</span><span class="o">.</span><span class="na">topRunningActivity</span><span class="o">()</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Skip the task if no running activity and continue resuming next task.</span>
<span class="k">continue</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// Otherwise, assuming everything behind this task should also be invisible.</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">someActivityResumed</span> <span class="o">|=</span> <span class="n">child</span><span class="o">.</span><span class="na">resumeTopActivityUncheckedLocked</span><span class="o">(</span><span class="n">prev</span><span class="o">,</span> <span class="n">options</span><span class="o">,</span>
<span class="n">deferPause</span><span class="o">);</span>
<span class="c1">// Doing so in order to prevent IndexOOB since hierarchy might changes while</span>
<span class="c1">// resuming activities, for example dismissing split-screen while starting</span>
<span class="c1">// non-resizeable activity.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">idx</span> <span class="o">>=</span> <span class="n">mChildren</span><span class="o">.</span><span class="na">size</span><span class="o">())</span> <span class="o">{</span>
<span class="n">idx</span> <span class="o">=</span> <span class="n">mChildren</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// When resuming the top activity, it may be necessary to pause the top activity (for</span>
<span class="c1">// example, returning to the lock screen. We suppress the normal pause logic in</span>
<span class="c1">// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the</span>
<span class="c1">// end. We call the {@link ActivityTaskSupervisor#checkReadyForSleepLocked} again here</span>
<span class="c1">// to ensure any necessary pause logic occurs. In the case where the Activity will be</span>
<span class="c1">// shown regardless of the lock screen, the call to</span>
<span class="c1">// {@link ActivityTaskSupervisor#checkReadyForSleepLocked} is skipped.</span>
<span class="kd">final</span> <span class="nc">ActivityRecord</span> <span class="n">next</span> <span class="o">=</span> <span class="n">topRunningActivity</span><span class="o">(</span><span class="kc">true</span> <span class="cm">/* focusableOnly */</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">next</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="o">!</span><span class="n">next</span><span class="o">.</span><span class="na">canTurnScreenOn</span><span class="o">())</span> <span class="o">{</span>
<span class="n">checkReadyForSleep</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mInResumeTopActivity</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">someActivityResumed</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>最终会跟进到 <code class="language-plaintext highlighter-rouge">TaskFragment</code> 当中:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td class="rouge-code"><pre><span class="kd">final</span> <span class="kt">boolean</span> <span class="nf">resumeTopActivity</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">prev</span><span class="o">,</span> <span class="nc">ActivityOptions</span> <span class="n">options</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">deferPause</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">next</span><span class="o">.</span><span class="na">attachedToProcess</span><span class="o">())</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// Whoops, need to restart this activity!</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">next</span><span class="o">.</span><span class="na">hasBeenLaunched</span><span class="o">)</span> <span class="o">{</span>
<span class="n">next</span><span class="o">.</span><span class="na">hasBeenLaunched</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="no">SHOW_APP_STARTING_PREVIEW</span><span class="o">)</span> <span class="o">{</span>
<span class="n">next</span><span class="o">.</span><span class="na">showStartingWindow</span><span class="o">(</span><span class="kc">false</span> <span class="cm">/* taskSwich */</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="no">DEBUG_SWITCH</span><span class="o">)</span> <span class="nc">Slog</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG_SWITCH</span><span class="o">,</span> <span class="s">"Restarting: "</span> <span class="o">+</span> <span class="n">next</span><span class="o">);</span>
<span class="o">}</span>
<span class="nc">ProtoLog</span><span class="o">.</span><span class="na">d</span><span class="o">(</span><span class="no">WM_DEBUG_STATES</span><span class="o">,</span> <span class="s">"resumeTopActivity: Restarting %s"</span><span class="o">,</span> <span class="n">next</span><span class="o">);</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">startSpecificActivity</span><span class="o">(</span><span class="n">next</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>重点看下 <code class="language-plaintext highlighter-rouge">ActivityTaskSupervisor#startSpecificActivity</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">startSpecificActivity</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">andResume</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">checkConfig</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Is this activity's application already running?</span>
<span class="kd">final</span> <span class="nc">WindowProcessController</span> <span class="n">wpc</span> <span class="o">=</span>
<span class="n">mService</span><span class="o">.</span><span class="na">getProcessController</span><span class="o">(</span><span class="n">r</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">r</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">applicationInfo</span><span class="o">.</span><span class="na">uid</span><span class="o">);</span>
<span class="kt">boolean</span> <span class="n">knownToBeDead</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">wpc</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">wpc</span><span class="o">.</span><span class="na">hasThread</span><span class="o">())</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">realStartActivityLocked</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">wpc</span><span class="o">,</span> <span class="n">andResume</span><span class="o">,</span> <span class="n">checkConfig</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RemoteException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">w</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception when starting activity "</span>
<span class="o">+</span> <span class="n">r</span><span class="o">.</span><span class="na">intent</span><span class="o">.</span><span class="na">getComponent</span><span class="o">().</span><span class="na">flattenToShortString</span><span class="o">(),</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// If a dead object exception was thrown -- fall through to</span>
<span class="c1">// restart the application.</span>
<span class="n">knownToBeDead</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="c1">// Remove the process record so it won't be considered as alive.</span>
<span class="n">mService</span><span class="o">.</span><span class="na">mProcessNames</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">wpc</span><span class="o">.</span><span class="na">mName</span><span class="o">,</span> <span class="n">wpc</span><span class="o">.</span><span class="na">mUid</span><span class="o">);</span>
<span class="n">mService</span><span class="o">.</span><span class="na">mProcessMap</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">wpc</span><span class="o">.</span><span class="na">getPid</span><span class="o">());</span>
<span class="o">}</span>
<span class="n">r</span><span class="o">.</span><span class="na">notifyUnknownVisibilityLaunchedForKeyguardTransition</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">isTop</span> <span class="o">=</span> <span class="n">andResume</span> <span class="o">&&</span> <span class="n">r</span><span class="o">.</span><span class="na">isTopRunningActivity</span><span class="o">();</span>
<span class="n">mService</span><span class="o">.</span><span class="na">startProcessAsync</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="n">isTop</span><span class="o">,</span>
<span class="n">isTop</span> <span class="o">?</span> <span class="nc">HostingRecord</span><span class="o">.</span><span class="na">HOSTING_TYPE_TOP_ACTIVITY</span>
<span class="o">:</span> <span class="nc">HostingRecord</span><span class="o">.</span><span class="na">HOSTING_TYPE_ACTIVITY</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>跟踪了方法调用栈这么久终于找到“罪魁祸首”了,startSpecificActivity 方法做了两件事:</p>
<ul>
<li>如果 Activity 的进程已经启动,则直接执行 <code class="language-plaintext highlighter-rouge">realStartActivityLocked</code> 来启动 Activity(通常是启动一般已运行进程的 Activity);</li>
<li>如果 Activity 的进程尚未启动,那么需要先执行 <code class="language-plaintext highlighter-rouge">ActivityTaskManagerService#startProcessAsync</code> 创建进程(通常是进程尚未启动的情况,例如初次打开 APP)。</li>
</ul>
<p>上面的 Activity 在本场景下指代 Launcher 进程的首个 Activity,由于是第一次启动该 Activity,所以进程肯定还没有创建,我们先去看下 startProcessAsync 中是如何创建 Launcher 进程的:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">startProcessAsync</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">activity</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">isTop</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">hostingType</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">isTagEnabled</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">,</span> <span class="s">"dispatchingStartProcess:"</span>
<span class="o">+</span> <span class="n">activity</span><span class="o">.</span><span class="na">processName</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Post message to start process to avoid possible deadlock of calling into AMS with the</span>
<span class="c1">// ATMS lock held.</span>
<span class="kd">final</span> <span class="nc">Message</span> <span class="n">m</span> <span class="o">=</span> <span class="nc">PooledLambda</span><span class="o">.</span><span class="na">obtainMessage</span><span class="o">(</span><span class="nl">ActivityManagerInternal:</span><span class="o">:</span><span class="n">startProcess</span><span class="o">,</span>
<span class="n">mAmInternal</span><span class="o">,</span> <span class="n">activity</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">activity</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">applicationInfo</span><span class="o">,</span> <span class="n">knownToBeDead</span><span class="o">,</span>
<span class="n">isTop</span><span class="o">,</span> <span class="n">hostingType</span><span class="o">,</span> <span class="n">activity</span><span class="o">.</span><span class="na">intent</span><span class="o">.</span><span class="na">getComponent</span><span class="o">());</span>
<span class="n">mH</span><span class="o">.</span><span class="na">sendMessage</span><span class="o">(</span><span class="n">m</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>由此可见,这里通过 Message-Handler 来发送创建进程的消息,消息接收处理是通过设置的 Callback,最终回调给 <code class="language-plaintext highlighter-rouge">ActivityManagerInternal::startProcess</code>:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
</pre></td><td class="rouge-code"><pre><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">startProcess</span><span class="o">(</span><span class="nc">String</span> <span class="n">processName</span><span class="o">,</span> <span class="nc">ApplicationInfo</span> <span class="n">info</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">knownToBeDead</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isTop</span><span class="o">,</span> <span class="nc">String</span> <span class="n">hostingType</span><span class="o">,</span> <span class="nc">ComponentName</span> <span class="n">hostingName</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">isTagEnabled</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">,</span> <span class="s">"startProcess:"</span>
<span class="o">+</span> <span class="n">processName</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="nc">ActivityManagerService</span><span class="o">.</span><span class="na">this</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// If the process is known as top app, set a hint so when the process is</span>
<span class="c1">// started, the top priority can be applied immediately to avoid cpu being</span>
<span class="c1">// preempted by other processes before attaching the process of top app.</span>
<span class="n">startProcessLocked</span><span class="o">(</span><span class="n">processName</span><span class="o">,</span> <span class="n">info</span><span class="o">,</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="mi">0</span> <span class="cm">/* intentFlags */</span><span class="o">,</span>
<span class="k">new</span> <span class="nf">HostingRecord</span><span class="o">(</span><span class="n">hostingType</span><span class="o">,</span> <span class="n">hostingName</span><span class="o">,</span> <span class="n">isTop</span><span class="o">),</span>
<span class="no">ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE</span><span class="o">,</span> <span class="kc">false</span> <span class="cm">/* allowWhileBooting */</span><span class="o">,</span>
<span class="kc">false</span> <span class="cm">/* isolated */</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@GuardedBy</span><span class="o">(</span><span class="s">"this"</span><span class="o">)</span>
<span class="kd">final</span> <span class="nc">ProcessRecord</span> <span class="nf">startProcessLocked</span><span class="o">(</span><span class="nc">String</span> <span class="n">processName</span><span class="o">,</span>
<span class="nc">ApplicationInfo</span> <span class="n">info</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="kt">int</span> <span class="n">intentFlags</span><span class="o">,</span>
<span class="nc">HostingRecord</span> <span class="n">hostingRecord</span><span class="o">,</span> <span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">allowWhileBooting</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isolated</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">mProcessList</span><span class="o">.</span><span class="na">startProcessLocked</span><span class="o">(</span><span class="n">processName</span><span class="o">,</span> <span class="n">info</span><span class="o">,</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="n">intentFlags</span><span class="o">,</span>
<span class="n">hostingRecord</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">allowWhileBooting</span><span class="o">,</span> <span class="n">isolated</span><span class="o">,</span> <span class="mi">0</span> <span class="cm">/* isolatedUid */</span><span class="o">,</span>
<span class="kc">false</span> <span class="cm">/* isSdkSandbox */</span><span class="o">,</span> <span class="mi">0</span> <span class="cm">/* sdkSandboxClientAppUid */</span><span class="o">,</span>
<span class="kc">null</span> <span class="cm">/* sdkSandboxClientAppPackage */</span><span class="o">,</span>
<span class="kc">null</span> <span class="cm">/* ABI override */</span><span class="o">,</span> <span class="kc">null</span> <span class="cm">/* entryPoint */</span><span class="o">,</span>
<span class="kc">null</span> <span class="cm">/* entryPointArgs */</span><span class="o">,</span> <span class="kc">null</span> <span class="cm">/* crashHandler */</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>接着执行到 <code class="language-plaintext highlighter-rouge">ProcessList#startProcessLocked</code> :</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/am/ProcessList.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
</pre></td><td class="rouge-code"><pre><span class="nc">ProcessRecord</span> <span class="nf">startProcessLocked</span><span class="o">(</span><span class="nc">String</span> <span class="n">processName</span><span class="o">,</span> <span class="nc">ApplicationInfo</span> <span class="n">info</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="kt">int</span> <span class="n">intentFlags</span><span class="o">,</span> <span class="nc">HostingRecord</span> <span class="n">hostingRecord</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">allowWhileBooting</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">isolated</span><span class="o">,</span> <span class="kt">int</span> <span class="n">isolatedUid</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isSdkSandbox</span><span class="o">,</span> <span class="kt">int</span> <span class="n">sdkSandboxUid</span><span class="o">,</span> <span class="nc">String</span> <span class="n">sdkSandboxClientAppPackage</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">abiOverride</span><span class="o">,</span> <span class="nc">String</span> <span class="n">entryPoint</span><span class="o">,</span> <span class="nc">String</span><span class="o">[]</span> <span class="n">entryPointArgs</span><span class="o">,</span> <span class="nc">Runnable</span> <span class="n">crashHandler</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">long</span> <span class="n">startTime</span> <span class="o">=</span> <span class="nc">SystemClock</span><span class="o">.</span><span class="na">uptimeMillis</span><span class="o">();</span>
<span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">isolated</span><span class="o">)</span> <span class="o">{</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">getProcessRecordLocked</span><span class="o">(</span><span class="n">processName</span><span class="o">,</span> <span class="n">info</span><span class="o">.</span><span class="na">uid</span><span class="o">);</span>
<span class="n">checkSlow</span><span class="o">(</span><span class="n">startTime</span><span class="o">,</span> <span class="s">"startProcess: after getProcessRecord"</span><span class="o">);</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// If this is an isolated process, it can't re-use an existing process.</span>
<span class="n">app</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">success</span> <span class="o">=</span>
<span class="n">startProcessLocked</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">hostingRecord</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">abiOverride</span><span class="o">);</span>
<span class="n">checkSlow</span><span class="o">(</span><span class="n">startTime</span><span class="o">,</span> <span class="s">"startProcess: done starting proc!"</span><span class="o">);</span>
<span class="k">return</span> <span class="n">success</span> <span class="o">?</span> <span class="n">app</span> <span class="o">:</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**
* @return {@code true} if process start is successful, false otherwise.
*/</span>
<span class="nd">@GuardedBy</span><span class="o">(</span><span class="s">"mService"</span><span class="o">)</span>
<span class="kt">boolean</span> <span class="nf">startProcessLocked</span><span class="o">(</span><span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">,</span> <span class="nc">HostingRecord</span> <span class="n">hostingRecord</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">disableHiddenApiChecks</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">disableTestApiChecks</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">abiOverride</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">isPendingStart</span><span class="o">())</span> <span class="o">{</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="nc">ApplicationInfo</span> <span class="n">definingAppInfo</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">hostingRecord</span><span class="o">.</span><span class="na">getDefiningPackageName</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">definingAppInfo</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ApplicationInfo</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">);</span>
<span class="n">definingAppInfo</span><span class="o">.</span><span class="na">packageName</span> <span class="o">=</span> <span class="n">hostingRecord</span><span class="o">.</span><span class="na">getDefiningPackageName</span><span class="o">();</span>
<span class="n">definingAppInfo</span><span class="o">.</span><span class="na">uid</span> <span class="o">=</span> <span class="n">uid</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">definingAppInfo</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">runtimeFlags</span> <span class="o">|=</span> <span class="nc">Zygote</span><span class="o">.</span><span class="na">getMemorySafetyRuntimeFlags</span><span class="o">(</span>
<span class="n">definingAppInfo</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">processInfo</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="n">mPlatformCompat</span><span class="o">);</span>
<span class="o">...</span>
<span class="c1">// 进程入口函数所在类 </span>
<span class="kd">final</span> <span class="nc">String</span> <span class="n">entryPoint</span> <span class="o">=</span> <span class="s">"android.app.ActivityThread"</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">startProcessLocked</span><span class="o">(</span><span class="n">hostingRecord</span><span class="o">,</span> <span class="n">entryPoint</span><span class="o">,</span> <span class="n">app</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span>
<span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span> <span class="n">requiredAbi</span><span class="o">,</span>
<span class="n">instructionSet</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="n">startUptime</span><span class="o">,</span> <span class="n">startElapsedTime</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RuntimeException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="nc">ActivityManagerService</span><span class="o">.</span><span class="na">TAG</span><span class="o">,</span> <span class="s">"Failure starting process "</span> <span class="o">+</span> <span class="n">app</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="n">mService</span><span class="o">.</span><span class="na">forceStopPackageLocked</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">packageName</span><span class="o">,</span> <span class="nc">UserHandle</span><span class="o">.</span><span class="na">getAppId</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">uid</span><span class="o">),</span>
<span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">userId</span><span class="o">,</span> <span class="s">"start failure"</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="nf">startProcessLocked</span><span class="o">(</span><span class="nc">HostingRecord</span> <span class="n">hostingRecord</span><span class="o">,</span> <span class="nc">String</span> <span class="n">entryPoint</span><span class="o">,</span> <span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">uid</span><span class="o">,</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span> <span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">seInfo</span><span class="o">,</span> <span class="nc">String</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span>
<span class="kt">long</span> <span class="n">startUptime</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startElapsedTime</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mService</span><span class="o">.</span><span class="na">mConstants</span><span class="o">.</span><span class="na">FLAG_PROCESS_START_ASYNC</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="n">startResult</span> <span class="o">=</span> <span class="n">startProcess</span><span class="o">(</span><span class="n">hostingRecord</span><span class="o">,</span>
<span class="n">entryPoint</span><span class="o">,</span> <span class="n">app</span><span class="o">,</span>
<span class="n">uid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="n">requiredAbi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="n">startUptime</span><span class="o">);</span>
<span class="n">handleProcessStartedLocked</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">startResult</span><span class="o">.</span><span class="na">pid</span><span class="o">,</span> <span class="n">startResult</span><span class="o">.</span><span class="na">usingWrapper</span><span class="o">,</span>
<span class="n">startSeq</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RuntimeException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="na">getPid</span><span class="o">()</span> <span class="o">></span> <span class="mi">0</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/**
* Main handler routine to start the given process from the ProcStartHandler.
*
* <p>Note: this function doesn't hold the global AM lock intentionally.</p>
*/</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">handleProcessStart</span><span class="o">(</span><span class="kd">final</span> <span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">entryPoint</span><span class="o">,</span>
<span class="kd">final</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="kd">final</span> <span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">long</span> <span class="n">startSeq</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Runnable</span> <span class="n">startRunnable</span> <span class="o">=</span> <span class="o">()</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="n">startResult</span> <span class="o">=</span> <span class="n">startProcess</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getHostingRecord</span><span class="o">(),</span>
<span class="n">entryPoint</span><span class="o">,</span> <span class="n">app</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartUid</span><span class="o">(),</span> <span class="n">gids</span><span class="o">,</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="n">mountExternal</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">getSeInfo</span><span class="o">(),</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getStartTime</span><span class="o">());</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mService</span><span class="o">)</span> <span class="o">{</span>
<span class="n">handleProcessStartedLocked</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">startResult</span><span class="o">,</span> <span class="n">startSeq</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RuntimeException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="c1">// Use local reference since we are not using locks here</span>
<span class="kd">final</span> <span class="nc">ProcessRecord</span> <span class="n">predecessor</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="na">mPredecessor</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">predecessor</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">predecessor</span><span class="o">.</span><span class="na">getDyingPid</span><span class="o">()</span> <span class="o">></span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">handleProcessStartWithPredecessor</span><span class="o">(</span><span class="n">predecessor</span><span class="o">,</span> <span class="n">startRunnable</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// Kick off the process start for real.</span>
<span class="n">startRunnable</span><span class="o">.</span><span class="na">run</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="nf">startProcess</span><span class="o">(</span><span class="nc">HostingRecord</span> <span class="n">hostingRecord</span><span class="o">,</span> <span class="nc">String</span> <span class="n">entryPoint</span><span class="o">,</span>
<span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">,</span> <span class="kt">int</span> <span class="n">uid</span><span class="o">,</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span> <span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="nc">String</span> <span class="n">seInfo</span><span class="o">,</span> <span class="nc">String</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startTime</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">,</span> <span class="s">"Start proc: "</span> <span class="o">+</span>
<span class="n">app</span><span class="o">.</span><span class="na">processName</span><span class="o">);</span>
<span class="o">...</span>
<span class="kd">final</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="n">startResult</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">regularZygote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">hostingRecord</span><span class="o">.</span><span class="na">usesWebviewZygote</span><span class="o">())</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">hostingRecord</span><span class="o">.</span><span class="na">usesAppZygote</span><span class="o">())</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">AppZygote</span> <span class="n">appZygote</span> <span class="o">=</span> <span class="n">createAppZygoteForProcessIfNeeded</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="c1">// We can't isolate app data and storage data as parent zygote already did that.</span>
<span class="n">startResult</span> <span class="o">=</span> <span class="n">appZygote</span><span class="o">.</span><span class="na">getProcess</span><span class="o">().</span><span class="na">start</span><span class="o">(</span><span class="n">entryPoint</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">targetSdkVersion</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">dataDir</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">packageName</span><span class="o">,</span>
<span class="cm">/*zygotePolicyFlags=*/</span> <span class="no">ZYGOTE_POLICY_FLAG_EMPTY</span><span class="o">,</span> <span class="n">isTopApp</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getDisabledCompatChanges</span><span class="o">(),</span> <span class="n">pkgDataInfoMap</span><span class="o">,</span> <span class="n">allowlistedAppDataInfoMap</span><span class="o">,</span>
<span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span>
<span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="no">PROC_START_SEQ_IDENT</span> <span class="o">+</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartSeq</span><span class="o">()});</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">regularZygote</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">startResult</span> <span class="o">=</span> <span class="nc">Process</span><span class="o">.</span><span class="na">start</span><span class="o">(</span><span class="n">entryPoint</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">targetSdkVersion</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span> <span class="n">requiredAbi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">dataDir</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">packageName</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="n">isTopApp</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">getDisabledCompatChanges</span><span class="o">(),</span> <span class="n">pkgDataInfoMap</span><span class="o">,</span>
<span class="n">allowlistedAppDataInfoMap</span><span class="o">,</span> <span class="n">bindMountAppsData</span><span class="o">,</span> <span class="n">bindMountAppStorageDirs</span><span class="o">,</span>
<span class="k">new</span> <span class="nc">String</span><span class="o">[]{</span><span class="no">PROC_START_SEQ_IDENT</span> <span class="o">+</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartSeq</span><span class="o">()});</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="k">return</span> <span class="n">startResult</span><span class="o">;</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>经过重重方法调用,最终抵达了进程创建的目的地,它的前置方法 <code class="language-plaintext highlighter-rouge">startProcessLocked</code> 主要用于包装进程启动相关参数信息及合并状态信息。值得注意的是,参数中的 entryPoint 这里特指 <code class="language-plaintext highlighter-rouge">android.app.ActivityThread</code>,表示后续在创建进程时的入口类。我们主要关注一下上面的 <code class="language-plaintext highlighter-rouge">startProcess</code> 方法,它内部涉及到两个不同的创建新进程的分支,分别为:</p>
<ul>
<li>appZygote:AppZygote 进程来孵化新进程,与常规 zygote 创建的应用相比受到更多限制;</li>
<li>regularZygote:常规的 zygote32/zygote64 进程,是所有 Android 应用的父进程。</li>
</ul>
<p>我们这里着重关注 regularZygote 的分支,具体看下内部通过 <code class="language-plaintext highlighter-rouge">Process.start</code> 创建进程的实现:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/os/Process.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* State associated with the zygote process.
* @hide
*/</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="nc">ZygoteProcess</span> <span class="no">ZYGOTE_PROCESS</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ZygoteProcess</span><span class="o">();</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">ProcessStartResult</span> <span class="nf">start</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">processClass</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">niceName</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">uid</span><span class="o">,</span> <span class="kt">int</span> <span class="n">gid</span><span class="o">,</span> <span class="nd">@Nullable</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">targetSdkVersion</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">abi</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">appDataDir</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">packageName</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isTopApp</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kt">long</span><span class="o">[]</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">pkgDataInfoMap</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">whitelistedDataInfoMap</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppsData</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppStorageDirs</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span><span class="o">[]</span> <span class="n">zygoteArgs</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="no">ZYGOTE_PROCESS</span><span class="o">.</span><span class="na">start</span><span class="o">(</span><span class="n">processClass</span><span class="o">,</span> <span class="n">niceName</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">gid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span>
<span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="n">targetSdkVersion</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="n">abi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="n">appDataDir</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="n">packageName</span><span class="o">,</span>
<span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">isTopApp</span><span class="o">,</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="n">pkgDataInfoMap</span><span class="o">,</span> <span class="n">whitelistedDataInfoMap</span><span class="o">,</span> <span class="n">bindMountAppsData</span><span class="o">,</span>
<span class="n">bindMountAppStorageDirs</span><span class="o">,</span> <span class="n">zygoteArgs</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>可以看到,<code class="language-plaintext highlighter-rouge">Process.start</code> 最终调用的是 <code class="language-plaintext highlighter-rouge">ZygoteProcess#start</code> 方法:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/os/ZygoteProcess.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="nf">start</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">processClass</span><span class="o">,</span>
<span class="kd">final</span> <span class="nc">String</span> <span class="n">niceName</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">uid</span><span class="o">,</span> <span class="kt">int</span> <span class="n">gid</span><span class="o">,</span> <span class="nd">@Nullable</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">targetSdkVersion</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">abi</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">appDataDir</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">packageName</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isTopApp</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kt">long</span><span class="o">[]</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">pkgDataInfoMap</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">allowlistedDataInfoList</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppsData</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppStorageDirs</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span><span class="o">[]</span> <span class="n">zygoteArgs</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// TODO (chriswailes): Is there a better place to check this value?</span>
<span class="k">if</span> <span class="o">(</span><span class="n">fetchUsapPoolEnabledPropWithMinInterval</span><span class="o">())</span> <span class="o">{</span>
<span class="n">informZygotesOfUsapPoolStatus</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">startViaZygote</span><span class="o">(</span><span class="n">processClass</span><span class="o">,</span> <span class="n">niceName</span><span class="o">,</span> <span class="n">uid</span><span class="o">,</span> <span class="n">gid</span><span class="o">,</span> <span class="n">gids</span><span class="o">,</span>
<span class="n">runtimeFlags</span><span class="o">,</span> <span class="n">mountExternal</span><span class="o">,</span> <span class="n">targetSdkVersion</span><span class="o">,</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="n">abi</span><span class="o">,</span> <span class="n">instructionSet</span><span class="o">,</span> <span class="n">appDataDir</span><span class="o">,</span> <span class="n">invokeWith</span><span class="o">,</span> <span class="cm">/*startChildZygote=*/</span> <span class="kc">false</span><span class="o">,</span>
<span class="n">packageName</span><span class="o">,</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="n">isTopApp</span><span class="o">,</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="n">pkgDataInfoMap</span><span class="o">,</span> <span class="n">allowlistedDataInfoList</span><span class="o">,</span> <span class="n">bindMountAppsData</span><span class="o">,</span>
<span class="n">bindMountAppStorageDirs</span><span class="o">,</span> <span class="n">zygoteArgs</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">ZygoteStartFailedEx</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="no">LOG_TAG</span><span class="o">,</span>
<span class="s">"Starting VM process through Zygote failed"</span><span class="o">);</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Starting VM process through Zygote failed"</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="nf">startViaZygote</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">processClass</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">niceName</span><span class="o">,</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">uid</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">gid</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kd">final</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">gids</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">runtimeFlags</span><span class="o">,</span> <span class="kt">int</span> <span class="n">mountExternal</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">targetSdkVersion</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">seInfo</span><span class="o">,</span>
<span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">abi</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">instructionSet</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">appDataDir</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">invokeWith</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">startChildZygote</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span> <span class="n">packageName</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isTopApp</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="kt">long</span><span class="o">[]</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">pkgDataInfoMap</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">Map</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Pair</span><span class="o"><</span><span class="nc">String</span><span class="o">,</span> <span class="nc">Long</span><span class="o">>></span>
<span class="n">allowlistedDataInfoList</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppsData</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">bindMountAppStorageDirs</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">String</span><span class="o">[]</span> <span class="n">extraArgs</span><span class="o">)</span>
<span class="kd">throws</span> <span class="nc">ZygoteStartFailedEx</span> <span class="o">{</span>
<span class="nc">ArrayList</span><span class="o"><</span><span class="nc">String</span><span class="o">></span> <span class="n">argsForZygote</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o"><>();</span>
<span class="o">...</span>
<span class="n">argsForZygote</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">processClass</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">extraArgs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Collections</span><span class="o">.</span><span class="na">addAll</span><span class="o">(</span><span class="n">argsForZygote</span><span class="o">,</span> <span class="n">extraArgs</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">synchronized</span><span class="o">(</span><span class="n">mLock</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// The USAP pool can not be used if the application will not use the systems graphics</span>
<span class="c1">// driver. If that driver is requested use the Zygote application start path.</span>
<span class="k">return</span> <span class="nf">zygoteSendArgsAndGetResult</span><span class="o">(</span><span class="n">openZygoteSocketIfNeeded</span><span class="o">(</span><span class="n">abi</span><span class="o">),</span>
<span class="n">zygotePolicyFlags</span><span class="o">,</span>
<span class="n">argsForZygote</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="nf">zygoteSendArgsAndGetResult</span><span class="o">(</span>
<span class="nc">ZygoteState</span> <span class="n">zygoteState</span><span class="o">,</span> <span class="kt">int</span> <span class="n">zygotePolicyFlags</span><span class="o">,</span> <span class="nd">@NonNull</span> <span class="nc">ArrayList</span><span class="o"><</span><span class="nc">String</span><span class="o">></span> <span class="n">args</span><span class="o">)</span>
<span class="kd">throws</span> <span class="nc">ZygoteStartFailedEx</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">return</span> <span class="nf">attemptZygoteSendArgsAndGetResult</span><span class="o">(</span><span class="n">zygoteState</span><span class="o">,</span> <span class="n">msgStr</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="nf">attemptZygoteSendArgsAndGetResult</span><span class="o">(</span>
<span class="nc">ZygoteState</span> <span class="n">zygoteState</span><span class="o">,</span> <span class="nc">String</span> <span class="n">msgStr</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">ZygoteStartFailedEx</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">BufferedWriter</span> <span class="n">zygoteWriter</span> <span class="o">=</span> <span class="n">zygoteState</span><span class="o">.</span><span class="na">mZygoteOutputWriter</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">DataInputStream</span> <span class="n">zygoteInputStream</span> <span class="o">=</span> <span class="n">zygoteState</span><span class="o">.</span><span class="na">mZygoteInputStream</span><span class="o">;</span>
<span class="n">zygoteWriter</span><span class="o">.</span><span class="na">write</span><span class="o">(</span><span class="n">msgStr</span><span class="o">);</span>
<span class="n">zygoteWriter</span><span class="o">.</span><span class="na">flush</span><span class="o">();</span>
<span class="c1">// Always read the entire result from the input stream to avoid leaving</span>
<span class="c1">// bytes in the stream for future process starts to accidentally stumble</span>
<span class="c1">// upon.</span>
<span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span> <span class="n">result</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Process</span><span class="o">.</span><span class="na">ProcessStartResult</span><span class="o">();</span>
<span class="n">result</span><span class="o">.</span><span class="na">pid</span> <span class="o">=</span> <span class="n">zygoteInputStream</span><span class="o">.</span><span class="na">readInt</span><span class="o">();</span>
<span class="n">result</span><span class="o">.</span><span class="na">usingWrapper</span> <span class="o">=</span> <span class="n">zygoteInputStream</span><span class="o">.</span><span class="na">readBoolean</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">result</span><span class="o">.</span><span class="na">pid</span> <span class="o"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ZygoteStartFailedEx</span><span class="o">(</span><span class="s">"fork() failed"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="n">zygoteState</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="no">LOG_TAG</span><span class="o">,</span> <span class="s">"IO Exception while communicating with Zygote - "</span>
<span class="o">+</span> <span class="n">ex</span><span class="o">.</span><span class="na">toString</span><span class="o">());</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ZygoteStartFailedEx</span><span class="o">(</span><span class="n">ex</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>总的来说,上面就是 zygote 孵化进程的过程。主要分为以下几个步骤:</p>
<ul>
<li>启动进程的参数封装</li>
<li>打开 Socket 套接字,并与 zygote 进程建立连接(详见 <code class="language-plaintext highlighter-rouge">openZygoteSocketIfNeeded</code>)</li>
<li>将进程的参数信息写入 <code class="language-plaintext highlighter-rouge">BufferedWriter</code>,并传输给 zygote 进程;通过 <code class="language-plaintext highlighter-rouge">DataInputStream</code> 来接收 zygote 进程返回的结果</li>
</ul>
<p>打开套接字并与 ZygoteServer 建立连接是在 openZygoteSocketIfNeeded 中完成的:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Tries to open a session socket to a Zygote process with a compatible ABI if one is not
* already open. If a compatible session socket is already open that session socket is returned.
* This function may block and may have to try connecting to multiple Zygotes to find the
* appropriate one. Requires that mLock be held.
*/</span>
<span class="kd">private</span> <span class="nc">ZygoteState</span> <span class="nf">openZygoteSocketIfNeeded</span><span class="o">(</span><span class="nc">String</span> <span class="n">abi</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">ZygoteStartFailedEx</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">attemptConnectionToPrimaryZygote</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">primaryZygoteState</span><span class="o">.</span><span class="na">matches</span><span class="o">(</span><span class="n">abi</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">primaryZygoteState</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mZygoteSecondarySocketAddress</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// The primary zygote didn't match. Try the secondary.</span>
<span class="n">attemptConnectionToSecondaryZygote</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">secondaryZygoteState</span><span class="o">.</span><span class="na">matches</span><span class="o">(</span><span class="n">abi</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">secondaryZygoteState</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">ioe</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ZygoteStartFailedEx</span><span class="o">(</span><span class="s">"Error connecting to zygote"</span><span class="o">,</span> <span class="n">ioe</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ZygoteStartFailedEx</span><span class="o">(</span><span class="s">"Unsupported zygote ABI: "</span> <span class="o">+</span> <span class="n">abi</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">attemptConnectionToPrimaryZygote</span><span class="o">()</span> <span class="kd">throws</span> <span class="nc">IOException</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">primaryZygoteState</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">primaryZygoteState</span><span class="o">.</span><span class="na">isClosed</span><span class="o">())</span> <span class="o">{</span>
<span class="n">primaryZygoteState</span> <span class="o">=</span>
<span class="nc">ZygoteState</span><span class="o">.</span><span class="na">connect</span><span class="o">(</span><span class="n">mZygoteSocketAddress</span><span class="o">,</span> <span class="n">mUsapPoolSocketAddress</span><span class="o">);</span>
<span class="n">maybeSetApiDenylistExemptions</span><span class="o">(</span><span class="n">primaryZygoteState</span><span class="o">,</span> <span class="kc">false</span><span class="o">);</span>
<span class="n">maybeSetHiddenApiAccessLogSampleRate</span><span class="o">(</span><span class="n">primaryZygoteState</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>如果没有打开 zygote 进程的套接字,则尝试开启并建立连接。下面看下 <code class="language-plaintext highlighter-rouge">ZygoteState</code> 类的静态方法 <code class="language-plaintext highlighter-rouge">connect</code>。</p>
<blockquote>
<p><em>frameworks/base/core/java/android/os/ZygoteProcess.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Create a new ZygoteState object by connecting to the given Zygote socket and saving the
* given USAP socket address.
*
* @param zygoteSocketAddress Zygote socket to connect to
* @param usapSocketAddress USAP socket address to save for later
* @return A new ZygoteState object containing a session socket for the given Zygote socket
* address
* @throws IOException
*/</span>
<span class="kd">static</span> <span class="nc">ZygoteState</span> <span class="nf">connect</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="nc">LocalSocketAddress</span> <span class="n">zygoteSocketAddress</span><span class="o">,</span>
<span class="nd">@Nullable</span> <span class="nc">LocalSocketAddress</span> <span class="n">usapSocketAddress</span><span class="o">)</span>
<span class="kd">throws</span> <span class="nc">IOException</span> <span class="o">{</span>
<span class="nc">DataInputStream</span> <span class="n">zygoteInputStream</span><span class="o">;</span>
<span class="nc">BufferedWriter</span> <span class="n">zygoteOutputWriter</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">LocalSocket</span> <span class="n">zygoteSessionSocket</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">LocalSocket</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">zygoteSocketAddress</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"zygoteSocketAddress can't be null"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">zygoteSessionSocket</span><span class="o">.</span><span class="na">connect</span><span class="o">(</span><span class="n">zygoteSocketAddress</span><span class="o">);</span>
<span class="n">zygoteInputStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DataInputStream</span><span class="o">(</span><span class="n">zygoteSessionSocket</span><span class="o">.</span><span class="na">getInputStream</span><span class="o">());</span>
<span class="n">zygoteOutputWriter</span> <span class="o">=</span>
<span class="k">new</span> <span class="nf">BufferedWriter</span><span class="o">(</span>
<span class="k">new</span> <span class="nf">OutputStreamWriter</span><span class="o">(</span><span class="n">zygoteSessionSocket</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">()),</span>
<span class="nc">Zygote</span><span class="o">.</span><span class="na">SOCKET_BUFFER_SIZE</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">zygoteSessionSocket</span><span class="o">.</span><span class="na">close</span><span class="o">();</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">IOException</span> <span class="n">ignore</span><span class="o">)</span> <span class="o">{</span> <span class="o">}</span>
<span class="k">throw</span> <span class="n">ex</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ZygoteState</span><span class="o">(</span><span class="n">zygoteSocketAddress</span><span class="o">,</span> <span class="n">usapSocketAddress</span><span class="o">,</span>
<span class="n">zygoteSessionSocket</span><span class="o">,</span> <span class="n">zygoteInputStream</span><span class="o">,</span> <span class="n">zygoteOutputWriter</span><span class="o">,</span>
<span class="n">getAbiList</span><span class="o">(</span><span class="n">zygoteOutputWriter</span><span class="o">,</span> <span class="n">zygoteInputStream</span><span class="o">));</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">ZygoteState</code> 类哟用于表示与 Zygote 进程通信的状态。假如传递给 connect 方法的实参是 <code class="language-plaintext highlighter-rouge">ZYGOTE_SOCKET</code>(即”zygote”),这代表要连接的远程地址。该方法中首先创建一个 <code class="language-plaintext highlighter-rouge">LocalSocket</code> 对象,接着调用其 <code class="language-plaintext highlighter-rouge">connect</code> 方法,连接成功之后,就可以得到套接字的输入和输出流,并将输入流其封装成 <code class="language-plaintext highlighter-rouge">DataInputStream</code> 对象,然后将输出流封装成 <code class="language-plaintext highlighter-rouge">BufferedWriter</code> 对象。接着就可以通过 <code class="language-plaintext highlighter-rouge">DataInputStream</code> 对象获得 Zygote 进程发送过来的消息,而通过 <code class="language-plaintext highlighter-rouge">BufferedWriter</code> 对象发送消息给 Zygote 进程。</p>
<p>那么问题来了,我们只知道了 socket 通信的一端,另外一端如何找到呢?其实上一篇关于<a href="https://dorck.cn/2023/04/22/android-initialization/">Android系统启动过程</a>的文章中在分析到 zygote 进程启动过程时已经提过一笔了:</p>
<blockquote>
<p><em>com.android.internal.os.ZygoteInit</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">argv</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ZygoteServer</span> <span class="n">zygoteServer</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">Runnable</span> <span class="n">caller</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">String</span> <span class="n">zygoteSocketName</span> <span class="o">=</span> <span class="s">"zygote"</span><span class="o">;</span>
<span class="o">...</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">i</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Accepting command socket connections"</span><span class="o">);</span>
<span class="c1">// The select loop returns early in the child process after a fork and</span>
<span class="c1">// loops forever in the zygote.</span>
<span class="n">caller</span> <span class="o">=</span> <span class="n">zygoteServer</span><span class="o">.</span><span class="na">runSelectLoop</span><span class="o">(</span><span class="n">abiList</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Throwable</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Log</span><span class="o">.</span><span class="na">e</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"System zygote died with fatal exception"</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
<span class="k">throw</span> <span class="n">ex</span><span class="o">;</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">zygoteServer</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">zygoteServer</span><span class="o">.</span><span class="na">closeServerSocket</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// We're in the child process and have exited the select loop. Proceed to execute the</span>
<span class="c1">// command.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">caller</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">caller</span><span class="o">.</span><span class="na">run</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>zygote 进程通过 <code class="language-plaintext highlighter-rouge">ZygoteServer#runSelectLoop</code> 来循环监听其他进程的 Socket 连接:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
</pre></td><td class="rouge-code"><pre> <span class="nc">Runnable</span> <span class="nf">runSelectLoop</span><span class="o">(</span><span class="nc">String</span> <span class="n">abiList</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ArrayList</span><span class="o"><</span><span class="nc">FileDescriptor</span><span class="o">></span> <span class="n">socketFDs</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o"><>();</span>
<span class="nc">ArrayList</span><span class="o"><</span><span class="nc">ZygoteConnection</span><span class="o">></span> <span class="n">peers</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ArrayList</span><span class="o"><>();</span>
<span class="c1">// sServerSocket是socket通信中的服务端,即zygote进程,保存到fds[0]</span>
<span class="n">socketFDs</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">mZygoteSocket</span><span class="o">.</span><span class="na">getFileDescriptor</span><span class="o">());</span>
<span class="n">peers</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
<span class="n">mUsapPoolRefillTriggerTimestamp</span> <span class="o">=</span> <span class="no">INVALID_TIMESTAMP</span><span class="o">;</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nc">StructPollfd</span><span class="o">[]</span> <span class="n">pollFDs</span><span class="o">;</span>
<span class="c1">// Allocate enough space for the poll structs, taking into account</span>
<span class="c1">// the state of the USAP pool for this Zygote (could be a</span>
<span class="c1">// regular Zygote, a WebView Zygote, or an AppZygote).</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mUsapPoolEnabled</span><span class="o">)</span> <span class="o">{</span>
<span class="n">usapPipeFDs</span> <span class="o">=</span> <span class="nc">Zygote</span><span class="o">.</span><span class="na">getUsapPipeFDs</span><span class="o">();</span>
<span class="n">pollFDs</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StructPollfd</span><span class="o">[</span><span class="n">socketFDs</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">+</span> <span class="mi">1</span> <span class="o">+</span> <span class="n">usapPipeFDs</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">pollFDs</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StructPollfd</span><span class="o">[</span><span class="n">socketFDs</span><span class="o">.</span><span class="na">size</span><span class="o">()];</span>
<span class="o">}</span>
<span class="cm">/*
* For reasons of correctness the USAP pool pipe and event FDs
* must be processed before the session and server sockets. This
* is to ensure that the USAP pool accounting information is
* accurate when handling other requests like API deny list
* exemptions.
*/</span>
<span class="kt">int</span> <span class="n">pollIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="nc">FileDescriptor</span> <span class="n">socketFD</span> <span class="o">:</span> <span class="n">socketFDs</span><span class="o">)</span> <span class="o">{</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StructPollfd</span><span class="o">();</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">fd</span> <span class="o">=</span> <span class="n">socketFD</span><span class="o">;</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">events</span> <span class="o">=</span> <span class="o">(</span><span class="kt">short</span><span class="o">)</span> <span class="no">POLLIN</span><span class="o">;</span>
<span class="o">++</span><span class="n">pollIndex</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">usapPoolEventFDIndex</span> <span class="o">=</span> <span class="n">pollIndex</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mUsapPoolEnabled</span><span class="o">)</span> <span class="o">{</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StructPollfd</span><span class="o">();</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">fd</span> <span class="o">=</span> <span class="n">mUsapPoolEventFD</span><span class="o">;</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">events</span> <span class="o">=</span> <span class="o">(</span><span class="kt">short</span><span class="o">)</span> <span class="no">POLLIN</span><span class="o">;</span>
<span class="o">++</span><span class="n">pollIndex</span><span class="o">;</span>
<span class="c1">// The usapPipeFDs array will always be filled in if the USAP Pool is enabled.</span>
<span class="k">assert</span> <span class="n">usapPipeFDs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">usapPipeFD</span> <span class="o">:</span> <span class="n">usapPipeFDs</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">FileDescriptor</span> <span class="n">managedFd</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">FileDescriptor</span><span class="o">();</span>
<span class="n">managedFd</span><span class="o">.</span><span class="na">setInt</span><span class="err">$</span><span class="o">(</span><span class="n">usapPipeFD</span><span class="o">);</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">]</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">StructPollfd</span><span class="o">();</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">fd</span> <span class="o">=</span> <span class="n">managedFd</span><span class="o">;</span>
<span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">events</span> <span class="o">=</span> <span class="o">(</span><span class="kt">short</span><span class="o">)</span> <span class="no">POLLIN</span><span class="o">;</span>
<span class="o">++</span><span class="n">pollIndex</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="n">pollTimeoutMs</span><span class="o">;</span>
<span class="o">...</span>
<span class="kt">int</span> <span class="n">pollReturnValue</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// 处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里</span>
<span class="n">pollReturnValue</span> <span class="o">=</span> <span class="nc">Os</span><span class="o">.</span><span class="na">poll</span><span class="o">(</span><span class="n">pollFDs</span><span class="o">,</span> <span class="n">pollTimeoutMs</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">ErrnoException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="s">"poll failed"</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">pollReturnValue</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// The poll returned zero results either when the timeout value has been exceeded</span>
<span class="c1">// or when a non-blocking poll is issued and no FDs are ready. In either case it</span>
<span class="c1">// is time to refill the pool. This will result in a duplicate assignment when</span>
<span class="c1">// the non-blocking poll returns zero results, but it avoids an additional</span>
<span class="c1">// conditional in the else branch.</span>
<span class="n">mUsapPoolRefillTriggerTimestamp</span> <span class="o">=</span> <span class="no">INVALID_TIMESTAMP</span><span class="o">;</span>
<span class="n">mUsapPoolRefillAction</span> <span class="o">=</span> <span class="nc">UsapPoolRefillAction</span><span class="o">.</span><span class="na">DELAYED</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="n">usapPoolFDRead</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">while</span> <span class="o">(--</span><span class="n">pollIndex</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// 采用I/O多路复用机制,当接收到客户端发出连接请求或者数据处理请求到来,则往下执行;</span>
<span class="c1">// 否则进入continue,跳出本次循环。</span>
<span class="k">if</span> <span class="o">((</span><span class="n">pollFDs</span><span class="o">[</span><span class="n">pollIndex</span><span class="o">].</span><span class="na">revents</span> <span class="o">&</span> <span class="no">POLLIN</span><span class="o">)</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">continue</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">pollIndex</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// 即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;</span>
<span class="c1">// 则创建ZygoteConnection对象,并添加到fds。</span>
<span class="nc">ZygoteConnection</span> <span class="n">newPeer</span> <span class="o">=</span> <span class="n">acceptCommandPeer</span><span class="o">(</span><span class="n">abiList</span><span class="o">);</span>
<span class="n">peers</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">newPeer</span><span class="o">);</span>
<span class="n">socketFDs</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">newPeer</span><span class="o">.</span><span class="na">getFileDescriptor</span><span class="o">());</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">pollIndex</span> <span class="o"><</span> <span class="n">usapPoolEventFDIndex</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// 从Zygote服务器套接字接受会话套接字</span>
<span class="k">try</span> <span class="o">{</span>
<span class="nc">ZygoteConnection</span> <span class="n">connection</span> <span class="o">=</span> <span class="n">peers</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">pollIndex</span><span class="o">);</span>
<span class="kt">boolean</span> <span class="n">multipleForksOK</span> <span class="o">=</span> <span class="o">!</span><span class="n">isUsapPoolEnabled</span><span class="o">()</span>
<span class="o">&&</span> <span class="nc">ZygoteHooks</span><span class="o">.</span><span class="na">isIndefiniteThreadSuspensionSafe</span><span class="o">();</span>
<span class="kd">final</span> <span class="nc">Runnable</span> <span class="n">command</span> <span class="o">=</span>
<span class="n">connection</span><span class="o">.</span><span class="na">processCommand</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">multipleForksOK</span><span class="o">);</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="c1">// Reset the child flag, in the event that the child process is a child-</span>
<span class="c1">// zygote. The flag will not be consulted this loop pass after the</span>
<span class="c1">// Runnable is returned.</span>
<span class="n">mIsForkChild</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p><code class="language-plaintext highlighter-rouge">mUsapPoolEnabled</code> 标识是否开启 USAP 机制。从Android Q(10)开始,Google 引入了一种新的机制:USAP(Unspecialized App Process)。通过 prefork 的方式提前创建好一批进程,当有应用启动时,直接将已经创建好的进程分配给它,从而省去了 fork 的动作,因此可以提升性能。后面将会有专门篇幅来研究 USAP 机制的运行原理,本文暂不做详细介绍。</p>
<p>其实,最终 ZygoteServer 会接收到来自 system_server 进程 AMS 创建新应用进程的消息,并通过 <code class="language-plaintext highlighter-rouge">ZygoteConnection#processCommand</code> 来处理并创建新进程:</p>
<blockquote>
<p><em>frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Reads a command from the command socket. If a child is successfully forked, a
* {@code Runnable} that calls the childs main method (or equivalent) is returned in the child
* process. {@code null} is always returned in the parent process (the zygote).
* If multipleOK is set, we may keep processing additional fork commands before returning.
*
* If the client closes the socket, an {@code EOF} condition is set, which callers can test
* for by calling {@code ZygoteConnection.isClosedByPeer}.
*/</span>
<span class="nc">Runnable</span> <span class="nf">processCommand</span><span class="o">(</span><span class="nc">ZygoteServer</span> <span class="n">zygoteServer</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">multipleOK</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ZygoteArguments</span> <span class="n">parsedArgs</span><span class="o">;</span>
<span class="k">try</span> <span class="o">(</span><span class="nc">ZygoteCommandBuffer</span> <span class="n">argBuffer</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ZygoteCommandBuffer</span><span class="o">(</span><span class="n">mSocket</span><span class="o">))</span> <span class="o">{</span>
<span class="k">while</span> <span class="o">(</span><span class="kc">true</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="kt">int</span> <span class="n">pid</span><span class="o">;</span>
<span class="nc">FileDescriptor</span> <span class="n">childPipeFd</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="nc">FileDescriptor</span> <span class="n">serverPipeFd</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">canPreloadApp</span><span class="o">()</span> <span class="o">&&</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mPreloadApp</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">rawParcelData</span> <span class="o">=</span> <span class="nc">Base64</span><span class="o">.</span><span class="na">getDecoder</span><span class="o">().</span><span class="na">decode</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mPreloadApp</span><span class="o">);</span>
<span class="nc">Parcel</span> <span class="n">appInfoParcel</span> <span class="o">=</span> <span class="nc">Parcel</span><span class="o">.</span><span class="na">obtain</span><span class="o">();</span>
<span class="n">appInfoParcel</span><span class="o">.</span><span class="na">unmarshall</span><span class="o">(</span><span class="n">rawParcelData</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">rawParcelData</span><span class="o">.</span><span class="na">length</span><span class="o">);</span>
<span class="n">appInfoParcel</span><span class="o">.</span><span class="na">setDataPosition</span><span class="o">(</span><span class="mi">0</span><span class="o">);</span>
<span class="nc">ApplicationInfo</span> <span class="n">appInfo</span> <span class="o">=</span>
<span class="nc">ApplicationInfo</span><span class="o">.</span><span class="na">CREATOR</span><span class="o">.</span><span class="na">createFromParcel</span><span class="o">(</span><span class="n">appInfoParcel</span><span class="o">);</span>
<span class="n">appInfoParcel</span><span class="o">.</span><span class="na">recycle</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">appInfo</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">handlePreloadApp</span><span class="o">(</span><span class="n">appInfo</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"Failed to deserialize --preload-app"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mInvokeWith</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mStartChildZygote</span>
<span class="o">||</span> <span class="o">!</span><span class="n">multipleOK</span> <span class="o">||</span> <span class="n">peer</span><span class="o">.</span><span class="na">getUid</span><span class="o">()</span> <span class="o">!=</span> <span class="nc">Process</span><span class="o">.</span><span class="na">SYSTEM_UID</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Continue using old code for now. TODO: Handle these cases in the other path.</span>
<span class="n">pid</span> <span class="o">=</span> <span class="nc">Zygote</span><span class="o">.</span><span class="na">forkAndSpecialize</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mUid</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mGid</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mGids</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mRuntimeFlags</span><span class="o">,</span> <span class="n">rlimits</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mMountExternal</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mSeInfo</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mNiceName</span><span class="o">,</span>
<span class="n">fdsToClose</span><span class="o">,</span> <span class="n">fdsToIgnore</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mStartChildZygote</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mInstructionSet</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mAppDataDir</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mIsTopApp</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mPkgDataInfoList</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mAllowlistedDataInfoList</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mBindMountAppDataDirs</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mBindMountAppStorageDirs</span><span class="o">);</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">pid</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// in child</span>
<span class="n">zygoteServer</span><span class="o">.</span><span class="na">setForkChild</span><span class="o">();</span>
<span class="n">zygoteServer</span><span class="o">.</span><span class="na">closeServerSocket</span><span class="o">();</span>
<span class="nc">IoUtils</span><span class="o">.</span><span class="na">closeQuietly</span><span class="o">(</span><span class="n">serverPipeFd</span><span class="o">);</span>
<span class="n">serverPipeFd</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">handleChildProc</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">,</span> <span class="n">childPipeFd</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mStartChildZygote</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// In the parent. A pid < 0 indicates a failure and will be handled in</span>
<span class="c1">// handleParentProc.</span>
<span class="nc">IoUtils</span><span class="o">.</span><span class="na">closeQuietly</span><span class="o">(</span><span class="n">childPipeFd</span><span class="o">);</span>
<span class="n">childPipeFd</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="n">handleParentProc</span><span class="o">(</span><span class="n">pid</span><span class="o">,</span> <span class="n">serverPipeFd</span><span class="o">);</span>
<span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">IoUtils</span><span class="o">.</span><span class="na">closeQuietly</span><span class="o">(</span><span class="n">childPipeFd</span><span class="o">);</span>
<span class="nc">IoUtils</span><span class="o">.</span><span class="na">closeQuietly</span><span class="o">(</span><span class="n">serverPipeFd</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="nc">ZygoteHooks</span><span class="o">.</span><span class="na">preFork</span><span class="o">();</span>
<span class="nc">Runnable</span> <span class="n">result</span> <span class="o">=</span> <span class="nc">Zygote</span><span class="o">.</span><span class="na">forkSimpleApps</span><span class="o">(</span><span class="n">argBuffer</span><span class="o">,</span>
<span class="n">zygoteServer</span><span class="o">.</span><span class="na">getZygoteSocketFileDescriptor</span><span class="o">(),</span>
<span class="n">peer</span><span class="o">.</span><span class="na">getUid</span><span class="o">(),</span> <span class="nc">Zygote</span><span class="o">.</span><span class="na">minChildUid</span><span class="o">(</span><span class="n">peer</span><span class="o">),</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mNiceName</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">result</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// parent; we finished some number of forks. Result is Boolean.</span>
<span class="c1">// We already did the equivalent of handleParentProc().</span>
<span class="nc">ZygoteHooks</span><span class="o">.</span><span class="na">postForkCommon</span><span class="o">();</span>
<span class="c1">// argBuffer contains a command not understood by forksimpleApps.</span>
<span class="k">continue</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="c1">// child; result is a Runnable.</span>
<span class="n">zygoteServer</span><span class="o">.</span><span class="na">setForkChild</span><span class="o">();</span>
<span class="nc">Zygote</span><span class="o">.</span><span class="na">setAppProcessName</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">,</span> <span class="no">TAG</span><span class="o">);</span> <span class="c1">// ??? Necessary?</span>
<span class="k">return</span> <span class="n">result</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>首先调用 ZygoteArguments 得到客户端发来的启动进程参数,接着进行权限检查,然后调用 <code class="language-plaintext highlighter-rouge">forkAndSpecialize</code> 创建新进程(native 层通过 fork() 来克隆出新进程,此时 native 层的进程其实相当于已经生成了),返回 pid 若为 0,则开始调用 <code class="language-plaintext highlighter-rouge">handleChildProc</code> 来处理子进程;如果返回 pid > 0,则开始调用 <code class="language-plaintext highlighter-rouge">handleParentProc</code> 来处理父进程。注意,这里并不是简单的 if-else 关系,调用 forkAndSpecialize 之后其实会返回两次,一次返回到父进程,另一次返回到新启动的子进程。至于为什么会返回两次,这里先埋下一个<strong>彩蛋</strong>,后续文章会填坑。接下来我们来继续看下如果返回的 pid 是 0,即在子进程返回的情况下,handleChildProc 做了些什么:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
</pre></td><td class="rouge-code"><pre><span class="kd">private</span> <span class="nc">Runnable</span> <span class="nf">handleChildProc</span><span class="o">(</span><span class="nc">ZygoteArguments</span> <span class="n">parsedArgs</span><span class="o">,</span>
<span class="nc">FileDescriptor</span> <span class="n">pipeFd</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">isZygote</span><span class="o">)</span> <span class="o">{</span>
<span class="cm">/*
* By the time we get here, the native code has closed the two actual Zygote
* socket connections, and substituted /dev/null in their place. The LocalSocket
* objects still need to be closed properly.
*/</span>
<span class="n">closeSocket</span><span class="o">();</span>
<span class="nc">Zygote</span><span class="o">.</span><span class="na">setAppProcessName</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">,</span> <span class="no">TAG</span><span class="o">);</span>
<span class="c1">// End of the postFork event.</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mInvokeWith</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">WrapperInit</span><span class="o">.</span><span class="na">execApplication</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mInvokeWith</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mNiceName</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mTargetSdkVersion</span><span class="o">,</span>
<span class="nc">VMRuntime</span><span class="o">.</span><span class="na">getCurrentInstructionSet</span><span class="o">(),</span>
<span class="n">pipeFd</span><span class="o">,</span> <span class="n">parsedArgs</span><span class="o">.</span><span class="na">mRemainingArgs</span><span class="o">);</span>
<span class="c1">// Should not get here.</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalStateException</span><span class="o">(</span><span class="s">"WrapperInit.execApplication unexpectedly returned"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">isZygote</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">ZygoteInit</span><span class="o">.</span><span class="na">zygoteInit</span><span class="o">(</span><span class="n">parsedArgs</span><span class="o">.</span><span class="na">mTargetSdkVersion</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mDisabledCompatChanges</span><span class="o">,</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mRemainingArgs</span><span class="o">,</span> <span class="kc">null</span> <span class="cm">/* classLoader */</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">return</span> <span class="nc">ZygoteInit</span><span class="o">.</span><span class="na">childZygoteInit</span><span class="o">(</span>
<span class="n">parsedArgs</span><span class="o">.</span><span class="na">mRemainingArgs</span> <span class="cm">/* classLoader */</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>由于我们创建的是应用进程,所以上方代码显然会执行到 <code class="language-plaintext highlighter-rouge">ZygoteInit.childZygoteInit</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* The main function called when starting a child zygote process. This is used as an alternative
* to zygoteInit(), which skips calling into initialization routines that start the Binder
* threadpool.
*/</span>
<span class="kd">static</span> <span class="nc">Runnable</span> <span class="nf">childZygoteInit</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">argv</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">RuntimeInit</span><span class="o">.</span><span class="na">Arguments</span> <span class="n">args</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">RuntimeInit</span><span class="o">.</span><span class="na">Arguments</span><span class="o">(</span><span class="n">argv</span><span class="o">);</span>
<span class="k">return</span> <span class="nc">RuntimeInit</span><span class="o">.</span><span class="na">findStaticMain</span><span class="o">(</span><span class="n">args</span><span class="o">.</span><span class="na">startClass</span><span class="o">,</span> <span class="n">args</span><span class="o">.</span><span class="na">startArgs</span><span class="o">,</span> <span class="cm">/* classLoader= */</span><span class="kc">null</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/</span>
<span class="kd">protected</span> <span class="kd">static</span> <span class="nc">Runnable</span> <span class="nf">findStaticMain</span><span class="o">(</span><span class="nc">String</span> <span class="n">className</span><span class="o">,</span> <span class="nc">String</span><span class="o">[]</span> <span class="n">argv</span><span class="o">,</span>
<span class="nc">ClassLoader</span> <span class="n">classLoader</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Class</span><span class="o"><?></span> <span class="n">cl</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">cl</span> <span class="o">=</span> <span class="nc">Class</span><span class="o">.</span><span class="na">forName</span><span class="o">(</span><span class="n">className</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="n">classLoader</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">ClassNotFoundException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Missing class when invoking static main "</span> <span class="o">+</span> <span class="n">className</span><span class="o">,</span>
<span class="n">ex</span><span class="o">);</span>
<span class="o">}</span>
<span class="nc">Method</span> <span class="n">m</span><span class="o">;</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">cl</span><span class="o">.</span><span class="na">getMethod</span><span class="o">(</span><span class="s">"main"</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Class</span><span class="o">[]</span> <span class="o">{</span> <span class="nc">String</span><span class="o">[].</span><span class="na">class</span> <span class="o">});</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">NoSuchMethodException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Missing static main on "</span> <span class="o">+</span> <span class="n">className</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">SecurityException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Problem getting static main on "</span> <span class="o">+</span> <span class="n">className</span><span class="o">,</span> <span class="n">ex</span><span class="o">);</span>
<span class="o">}</span>
<span class="kt">int</span> <span class="n">modifiers</span> <span class="o">=</span> <span class="n">m</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(!</span> <span class="o">(</span><span class="nc">Modifier</span><span class="o">.</span><span class="na">isStatic</span><span class="o">(</span><span class="n">modifiers</span><span class="o">)</span> <span class="o">&&</span> <span class="nc">Modifier</span><span class="o">.</span><span class="na">isPublic</span><span class="o">(</span><span class="n">modifiers</span><span class="o">)))</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Main method is not public and static on "</span> <span class="o">+</span> <span class="n">className</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">MethodAndArgsCaller</span><span class="o">(</span><span class="n">m</span><span class="o">,</span> <span class="n">argv</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>由上述代码可知,最终会通过反射的方式来为之前传递进来的 <code class="language-plaintext highlighter-rouge">processClass</code> 创建实例对象,根据上面流程的分析,这里的 processClass 显然是 <code class="language-plaintext highlighter-rouge">android.app.ActivityThread</code> 这个类,接着调用该类的 <code class="language-plaintext highlighter-rouge">main</code> 方法:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/app/ActivityThread.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="nc">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">,</span> <span class="s">"ActivityThreadMain"</span><span class="o">);</span>
<span class="c1">// Install selective syscall interception</span>
<span class="nc">AndroidOs</span><span class="o">.</span><span class="na">install</span><span class="o">();</span>
<span class="o">...</span>
<span class="nc">Looper</span><span class="o">.</span><span class="na">prepareMainLooper</span><span class="o">();</span>
<span class="o">...</span>
<span class="nc">ActivityThread</span> <span class="n">thread</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ActivityThread</span><span class="o">();</span>
<span class="n">thread</span><span class="o">.</span><span class="na">attach</span><span class="o">(</span><span class="kc">false</span><span class="o">,</span> <span class="n">startSeq</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sMainThreadHandler</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">sMainThreadHandler</span> <span class="o">=</span> <span class="n">thread</span><span class="o">.</span><span class="na">getHandler</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">// End of event ActivityThreadMain.</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="nc">Looper</span><span class="o">.</span><span class="na">loop</span><span class="o">();</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span><span class="s">"Main thread loop unexpectedly exited"</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>ActivityThread 的 <code class="language-plaintext highlighter-rouge">main</code> 中准备一个主线程的 Looper 并初始化消息队列,并创建一个 ActivityThread 实例,执行 <code class="language-plaintext highlighter-rouge">attach</code> 方法创建 Application 和绑定生命周期,最后开启主线程的消息循环。我们重点看下 attach 方法:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="rouge-code"><pre><span class="kd">private</span> <span class="kt">void</span> <span class="nf">attach</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">system</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startSeq</span><span class="o">)</span> <span class="o">{</span>
<span class="n">sCurrentActivityThread</span> <span class="o">=</span> <span class="k">this</span><span class="o">;</span>
<span class="n">mConfigurationController</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">ConfigurationController</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="n">mSystemThread</span> <span class="o">=</span> <span class="n">system</span><span class="o">;</span>
<span class="c1">// 此处 system 为 false</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">system</span><span class="o">)</span> <span class="o">{</span>
<span class="n">android</span><span class="o">.</span><span class="na">ddm</span><span class="o">.</span><span class="na">DdmHandleAppName</span><span class="o">.</span><span class="na">setAppName</span><span class="o">(</span><span class="s">"<pre-initialized>"</span><span class="o">,</span>
<span class="nc">UserHandle</span><span class="o">.</span><span class="na">myUserId</span><span class="o">());</span>
<span class="nc">RuntimeInit</span><span class="o">.</span><span class="na">setApplicationObject</span><span class="o">(</span><span class="n">mAppThread</span><span class="o">.</span><span class="na">asBinder</span><span class="o">());</span>
<span class="kd">final</span> <span class="nc">IActivityManager</span> <span class="n">mgr</span> <span class="o">=</span> <span class="nc">ActivityManager</span><span class="o">.</span><span class="na">getService</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mgr</span><span class="o">.</span><span class="na">attachApplication</span><span class="o">(</span><span class="n">mAppThread</span><span class="o">,</span> <span class="n">startSeq</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RemoteException</span> <span class="n">ex</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="n">ex</span><span class="o">.</span><span class="na">rethrowFromSystemServer</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>attach 中执行了 IActivityManager 的 <code class="language-plaintext highlighter-rouge">attachApplication</code> 方法,而 IActivityManager 其实是一个 Binder 接口,这里通过 ActivityManager.getService 获取它的代理服务 AMS,进而调用 <code class="language-plaintext highlighter-rouge">attachApplication</code> 来将 ActivityThread 内部类 ApplicationThread 绑定到 AMS,这样就可以通过 Binder IPC 间接控制应用进程了:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
</pre></td><td class="rouge-code"><pre><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kt">void</span> <span class="nf">attachApplication</span><span class="o">(</span><span class="nc">IApplicationThread</span> <span class="n">thread</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startSeq</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">thread</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">SecurityException</span><span class="o">(</span><span class="s">"Invalid application interface"</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="k">this</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">callingPid</span> <span class="o">=</span> <span class="nc">Binder</span><span class="o">.</span><span class="na">getCallingPid</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">int</span> <span class="n">callingUid</span> <span class="o">=</span> <span class="nc">Binder</span><span class="o">.</span><span class="na">getCallingUid</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">long</span> <span class="n">origId</span> <span class="o">=</span> <span class="nc">Binder</span><span class="o">.</span><span class="na">clearCallingIdentity</span><span class="o">();</span>
<span class="n">attachApplicationLocked</span><span class="o">(</span><span class="n">thread</span><span class="o">,</span> <span class="n">callingPid</span><span class="o">,</span> <span class="n">callingUid</span><span class="o">,</span> <span class="n">startSeq</span><span class="o">);</span>
<span class="nc">Binder</span><span class="o">.</span><span class="na">restoreCallingIdentity</span><span class="o">(</span><span class="n">origId</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">attachApplicationLocked</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="nc">IApplicationThread</span> <span class="n">thread</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">pid</span><span class="o">,</span> <span class="kt">int</span> <span class="n">callingUid</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startSeq</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Find the application record that is being attached... either via</span>
<span class="c1">// the pid if we are running in multiple processes, or just pull the</span>
<span class="c1">// next app record if we are emulating process with anonymous threads.</span>
<span class="nc">ProcessRecord</span> <span class="n">app</span><span class="o">;</span>
<span class="kt">long</span> <span class="n">startTime</span> <span class="o">=</span> <span class="nc">SystemClock</span><span class="o">.</span><span class="na">uptimeMillis</span><span class="o">();</span>
<span class="kt">long</span> <span class="n">bindApplicationTimeMillis</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">pid</span> <span class="o">!=</span> <span class="no">MY_PID</span> <span class="o">&&</span> <span class="n">pid</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mPidsSelfLocked</span><span class="o">)</span> <span class="o">{</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">mPidsSelfLocked</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">pid</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">app</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getStartUid</span><span class="o">()</span> <span class="o">!=</span> <span class="n">callingUid</span> <span class="o">||</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartSeq</span><span class="o">()</span> <span class="o">!=</span> <span class="n">startSeq</span><span class="o">))</span> <span class="o">{</span>
<span class="o">...</span>
<span class="c1">// If there is already an app occupying that pid that hasn't been cleaned up</span>
<span class="n">cleanUpApplicationRecordLocked</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">pid</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">,</span>
<span class="kc">true</span> <span class="cm">/*replacingPid*/</span><span class="o">,</span> <span class="kc">false</span> <span class="cm">/* fromBinderDied */</span><span class="o">);</span>
<span class="n">removePidLocked</span><span class="o">(</span><span class="n">pid</span><span class="o">,</span> <span class="n">app</span><span class="o">);</span>
<span class="n">app</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">app</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="k">try</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nc">ApplicationInfo</span> <span class="n">appInfo</span> <span class="o">=</span> <span class="n">instr</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">instr</span><span class="o">.</span><span class="na">mTargetInfo</span> <span class="o">:</span> <span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">;</span>
<span class="n">app</span><span class="o">.</span><span class="na">setCompat</span><span class="o">(</span><span class="n">compatibilityInfoForPackage</span><span class="o">(</span><span class="n">appInfo</span><span class="o">));</span>
<span class="k">if</span> <span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPoint</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// This is an isolated process which should just call an entry point instead of</span>
<span class="c1">// being bound to an application.</span>
<span class="n">thread</span><span class="o">.</span><span class="na">runIsolatedEntryPoint</span><span class="o">(</span>
<span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPoint</span><span class="o">(),</span> <span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPointArgs</span><span class="o">());</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">instr2</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">thread</span><span class="o">.</span><span class="na">bindApplication</span><span class="o">(</span><span class="n">processName</span><span class="o">,</span> <span class="n">appInfo</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">sdkSandboxClientAppVolumeUuid</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">sdkSandboxClientAppPackage</span><span class="o">,</span>
<span class="n">providerList</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">profilerInfo</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">testMode</span><span class="o">,</span>
<span class="n">mBinderTransactionTrackingEnabled</span><span class="o">,</span> <span class="n">enableTrackAllocation</span><span class="o">,</span>
<span class="n">isRestrictedBackupMode</span> <span class="o">||</span> <span class="o">!</span><span class="n">normalMode</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">isPersistent</span><span class="o">(),</span>
<span class="k">new</span> <span class="nf">Configuration</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getWindowProcessController</span><span class="o">().</span><span class="na">getConfiguration</span><span class="o">()),</span>
<span class="n">app</span><span class="o">.</span><span class="na">getCompat</span><span class="o">(),</span> <span class="n">getCommonServicesLocked</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">isolated</span><span class="o">),</span>
<span class="n">mCoreSettingsObserver</span><span class="o">.</span><span class="na">getCoreSettingsLocked</span><span class="o">(),</span>
<span class="n">buildSerial</span><span class="o">,</span> <span class="n">autofillOptions</span><span class="o">,</span> <span class="n">contentCaptureOptions</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getDisabledCompatChanges</span><span class="o">(),</span> <span class="n">serializedSystemFontMap</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getStartElapsedTime</span><span class="o">(),</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartUptime</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="c1">// Make app active after binding application or client may be running requests (e.g</span>
<span class="c1">// starting activities) before it is ready.</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mProcLock</span><span class="o">)</span> <span class="o">{</span>
<span class="n">app</span><span class="o">.</span><span class="na">makeActive</span><span class="o">(</span><span class="n">thread</span><span class="o">,</span> <span class="n">mProcessStats</span><span class="o">);</span>
<span class="n">checkTime</span><span class="o">(</span><span class="n">startTime</span><span class="o">,</span> <span class="s">"attachApplicationLocked: immediately after bindApplication"</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="n">didSomething</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="c1">// See if the top visible activity is waiting to run in this process...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">normalMode</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">didSomething</span> <span class="o">=</span> <span class="n">mAtmInternal</span><span class="o">.</span><span class="na">attachApplication</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getWindowProcessController</span><span class="o">());</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">wtf</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception thrown launching activities in "</span> <span class="o">+</span> <span class="n">app</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="n">badApp</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>ApplicationThread 作为 ActivityThread 的内部类,它是 <code class="language-plaintext highlighter-rouge">IApplicationThread</code> 这个 Binder 接口的最终实现类,即 ApplicationThread 内部实现了一套 AIDL 接口,这个接口与 Application 的创建、Activity 及 Service 等四大组件启动等息息相关。最终调用 <code class="language-plaintext highlighter-rouge">IApplicationThread</code> 的 <code class="language-plaintext highlighter-rouge">bindApplication</code> 方法:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/app/ActivityThread.java#ApplicationThread</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
</pre></td><td class="rouge-code"><pre><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kt">void</span> <span class="nf">bindApplication</span><span class="o">(</span><span class="nc">String</span> <span class="n">processName</span><span class="o">,</span> <span class="nc">ApplicationInfo</span> <span class="n">appInfo</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">sdkSandboxClientAppVolumeUuid</span><span class="o">,</span> <span class="nc">String</span> <span class="n">sdkSandboxClientAppPackage</span><span class="o">,</span>
<span class="nc">ProviderInfoList</span> <span class="n">providerList</span><span class="o">,</span> <span class="nc">ComponentName</span> <span class="n">instrumentationName</span><span class="o">,</span>
<span class="nc">ProfilerInfo</span> <span class="n">profilerInfo</span><span class="o">,</span> <span class="nc">Bundle</span> <span class="n">instrumentationArgs</span><span class="o">,</span>
<span class="nc">IInstrumentationWatcher</span> <span class="n">instrumentationWatcher</span><span class="o">,</span>
<span class="nc">IUiAutomationConnection</span> <span class="n">instrumentationUiConnection</span><span class="o">,</span> <span class="kt">int</span> <span class="n">debugMode</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">enableBinderTracking</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">trackAllocation</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isRestrictedBackupMode</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">persistent</span><span class="o">,</span> <span class="nc">Configuration</span> <span class="n">config</span><span class="o">,</span>
<span class="nc">CompatibilityInfo</span> <span class="n">compatInfo</span><span class="o">,</span> <span class="nc">Map</span> <span class="n">services</span><span class="o">,</span> <span class="nc">Bundle</span> <span class="n">coreSettings</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">buildSerial</span><span class="o">,</span> <span class="nc">AutofillOptions</span> <span class="n">autofillOptions</span><span class="o">,</span>
<span class="nc">ContentCaptureOptions</span> <span class="n">contentCaptureOptions</span><span class="o">,</span> <span class="kt">long</span><span class="o">[]</span> <span class="n">disabledCompatChanges</span><span class="o">,</span>
<span class="nc">SharedMemory</span> <span class="n">serializedSystemFontMap</span><span class="o">,</span>
<span class="kt">long</span> <span class="n">startRequestedElapsedTime</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startRequestedUptime</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nc">AppBindData</span> <span class="n">data</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">AppBindData</span><span class="o">();</span>
<span class="n">data</span><span class="o">.</span><span class="na">processName</span> <span class="o">=</span> <span class="n">processName</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">appInfo</span> <span class="o">=</span> <span class="n">appInfo</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">sdkSandboxClientAppVolumeUuid</span> <span class="o">=</span> <span class="n">sdkSandboxClientAppVolumeUuid</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">sdkSandboxClientAppPackage</span> <span class="o">=</span> <span class="n">sdkSandboxClientAppPackage</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">providers</span> <span class="o">=</span> <span class="n">providerList</span><span class="o">.</span><span class="na">getList</span><span class="o">();</span>
<span class="n">data</span><span class="o">.</span><span class="na">instrumentationName</span> <span class="o">=</span> <span class="n">instrumentationName</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">instrumentationArgs</span> <span class="o">=</span> <span class="n">instrumentationArgs</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">instrumentationWatcher</span> <span class="o">=</span> <span class="n">instrumentationWatcher</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">instrumentationUiAutomationConnection</span> <span class="o">=</span> <span class="n">instrumentationUiConnection</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">debugMode</span> <span class="o">=</span> <span class="n">debugMode</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">enableBinderTracking</span> <span class="o">=</span> <span class="n">enableBinderTracking</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">trackAllocation</span> <span class="o">=</span> <span class="n">trackAllocation</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">restrictedBackupMode</span> <span class="o">=</span> <span class="n">isRestrictedBackupMode</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">persistent</span> <span class="o">=</span> <span class="n">persistent</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">config</span> <span class="o">=</span> <span class="n">config</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">compatInfo</span> <span class="o">=</span> <span class="n">compatInfo</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">initProfilerInfo</span> <span class="o">=</span> <span class="n">profilerInfo</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">buildSerial</span> <span class="o">=</span> <span class="n">buildSerial</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">autofillOptions</span> <span class="o">=</span> <span class="n">autofillOptions</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">contentCaptureOptions</span> <span class="o">=</span> <span class="n">contentCaptureOptions</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">disabledCompatChanges</span> <span class="o">=</span> <span class="n">disabledCompatChanges</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">mSerializedSystemFontMap</span> <span class="o">=</span> <span class="n">serializedSystemFontMap</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">startRequestedElapsedTime</span> <span class="o">=</span> <span class="n">startRequestedElapsedTime</span><span class="o">;</span>
<span class="n">data</span><span class="o">.</span><span class="na">startRequestedUptime</span> <span class="o">=</span> <span class="n">startRequestedUptime</span><span class="o">;</span>
<span class="n">sendMessage</span><span class="o">(</span><span class="no">H</span><span class="o">.</span><span class="na">BIND_APPLICATION</span><span class="o">,</span> <span class="n">data</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>上面代码通过一个 Handler 实例发送 <code class="language-plaintext highlighter-rouge">H.BIND_APPLICATION</code> 消息,意味着需要构建和绑定 Application 对象。这个 Handler 同样是 ActivityThread 的内部类:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/app/ActivityThread.java#H</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="kd">class</span> <span class="nc">H</span> <span class="kd">extends</span> <span class="nc">Handler</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="no">BIND_APPLICATION</span> <span class="o">=</span> <span class="mi">110</span><span class="o">;</span>
<span class="o">...</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">handleMessage</span><span class="o">(</span><span class="nc">Message</span> <span class="n">msg</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="no">DEBUG_MESSAGES</span><span class="o">)</span> <span class="nc">Slog</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">">>> handling: "</span> <span class="o">+</span> <span class="n">codeToString</span><span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">what</span><span class="o">));</span>
<span class="k">switch</span> <span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">what</span><span class="o">)</span> <span class="o">{</span>
<span class="k">case</span> <span class="nl">BIND_APPLICATION:</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">,</span> <span class="s">"bindApplication"</span><span class="o">);</span>
<span class="nc">AppBindData</span> <span class="n">data</span> <span class="o">=</span> <span class="o">(</span><span class="nc">AppBindData</span><span class="o">)</span><span class="n">msg</span><span class="o">.</span><span class="na">obj</span><span class="o">;</span>
<span class="n">handleBindApplication</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="k">break</span><span class="o">;</span>
<span class="k">case</span> <span class="nl">EXIT_APPLICATION:</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mInitialApplication</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mInitialApplication</span><span class="o">.</span><span class="na">onTerminate</span><span class="o">();</span>
<span class="o">}</span>
<span class="nc">Looper</span><span class="o">.</span><span class="na">myLooper</span><span class="o">().</span><span class="na">quit</span><span class="o">();</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="nc">Object</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="na">obj</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">obj</span> <span class="k">instanceof</span> <span class="nc">SomeArgs</span><span class="o">)</span> <span class="o">{</span>
<span class="o">((</span><span class="nc">SomeArgs</span><span class="o">)</span> <span class="n">obj</span><span class="o">).</span><span class="na">recycle</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="no">DEBUG_MESSAGES</span><span class="o">)</span> <span class="nc">Slog</span><span class="o">.</span><span class="na">v</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"<<< done: "</span> <span class="o">+</span> <span class="n">codeToString</span><span class="o">(</span><span class="n">msg</span><span class="o">.</span><span class="na">what</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>通过跨进程通信,Application 的创建和绑定最终回到了主线程:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
</pre></td><td class="rouge-code"><pre><span class="kd">private</span> <span class="kt">void</span> <span class="nf">handleBindApplication</span><span class="o">(</span><span class="nc">AppBindData</span> <span class="n">data</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="c1">// Instrumentation info affects the class loader, so load it before</span>
<span class="c1">// setting up the app context.</span>
<span class="kd">final</span> <span class="nc">InstrumentationInfo</span> <span class="n">ii</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">data</span><span class="o">.</span><span class="na">instrumentationName</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">ii</span> <span class="o">=</span> <span class="n">prepareInstrumentation</span><span class="o">(</span><span class="n">data</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">ii</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="nc">ContextImpl</span> <span class="n">appContext</span> <span class="o">=</span> <span class="nc">ContextImpl</span><span class="o">.</span><span class="na">createAppContext</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">data</span><span class="o">.</span><span class="na">info</span><span class="o">);</span>
<span class="n">mConfigurationController</span><span class="o">.</span><span class="na">updateLocaleListFromAppContext</span><span class="o">(</span><span class="n">appContext</span><span class="o">);</span>
<span class="o">...</span>
<span class="c1">// Continue loading instrumentation.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">ii</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">initInstrumentation</span><span class="o">(</span><span class="n">ii</span><span class="o">,</span> <span class="n">data</span><span class="o">,</span> <span class="n">appContext</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">mInstrumentation</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">Instrumentation</span><span class="o">();</span>
<span class="n">mInstrumentation</span><span class="o">.</span><span class="na">basicInit</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Allow disk access during application and provider setup. This could</span>
<span class="c1">// block processing ordered broadcasts, but later processing would</span>
<span class="c1">// probably end up doing the same disk access.</span>
<span class="nc">Application</span> <span class="n">app</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">StrictMode</span><span class="o">.</span><span class="na">ThreadPolicy</span> <span class="n">savedPolicy</span> <span class="o">=</span> <span class="nc">StrictMode</span><span class="o">.</span><span class="na">allowThreadDiskWrites</span><span class="o">();</span>
<span class="kd">final</span> <span class="nc">StrictMode</span><span class="o">.</span><span class="na">ThreadPolicy</span> <span class="n">writesAllowedPolicy</span> <span class="o">=</span> <span class="nc">StrictMode</span><span class="o">.</span><span class="na">getThreadPolicy</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="c1">// If the app is being launched for full backup or restore, bring it up in</span>
<span class="c1">// a restricted environment with the base application class.</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">makeApplicationInner</span><span class="o">(</span><span class="n">data</span><span class="o">.</span><span class="na">restrictedBackupMode</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">...</span>
<span class="n">mInitialApplication</span> <span class="o">=</span> <span class="n">app</span><span class="o">;</span>
<span class="o">...</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mInstrumentation</span><span class="o">.</span><span class="na">callApplicationOnCreate</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">mInstrumentation</span><span class="o">.</span><span class="na">onException</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">e</span><span class="o">))</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">RuntimeException</span><span class="o">(</span>
<span class="s">"Unable to create application "</span> <span class="o">+</span> <span class="n">app</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getName</span><span class="o">()</span>
<span class="o">+</span> <span class="s">": "</span> <span class="o">+</span> <span class="n">e</span><span class="o">.</span><span class="na">toString</span><span class="o">(),</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>最终通过 LoadedApk 中的 <code class="language-plaintext highlighter-rouge">makeApplication</code> 方法来尝试创建 Application 对象并执行它的 <code class="language-plaintext highlighter-rouge">onCreate</code> 生命周期方法:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/app/LoadedApk.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="nc">Application</span> <span class="nf">makeApplicationInner</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">forceDefaultAppClass</span><span class="o">,</span>
<span class="nc">Instrumentation</span> <span class="n">instrumentation</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="nf">makeApplicationInner</span><span class="o">(</span><span class="n">forceDefaultAppClass</span><span class="o">,</span> <span class="n">instrumentation</span><span class="o">,</span>
<span class="cm">/* allowDuplicateInstances= */</span> <span class="kc">false</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="nc">Application</span> <span class="nf">makeApplicationInner</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">forceDefaultAppClass</span><span class="o">,</span>
<span class="nc">Instrumentation</span> <span class="n">instrumentation</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">allowDuplicateInstances</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mApplication</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">mApplication</span><span class="o">;</span>
<span class="o">}</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">,</span> <span class="s">"makeApplication"</span><span class="o">);</span>
<span class="o">...</span>
<span class="nc">Application</span> <span class="n">app</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="kd">final</span> <span class="nc">String</span> <span class="n">myProcessName</span> <span class="o">=</span> <span class="nc">Process</span><span class="o">.</span><span class="na">myProcessName</span><span class="o">();</span>
<span class="nc">String</span> <span class="n">appClass</span> <span class="o">=</span> <span class="n">mApplicationInfo</span><span class="o">.</span><span class="na">getCustomApplicationClassNameForProcess</span><span class="o">(</span>
<span class="n">myProcessName</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">forceDefaultAppClass</span> <span class="o">||</span> <span class="o">(</span><span class="n">appClass</span> <span class="o">==</span> <span class="kc">null</span><span class="o">))</span> <span class="o">{</span>
<span class="n">appClass</span> <span class="o">=</span> <span class="s">"android.app.Application"</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nc">ContextImpl</span> <span class="n">appContext</span> <span class="o">=</span> <span class="nc">ContextImpl</span><span class="o">.</span><span class="na">createAppContext</span><span class="o">(</span><span class="n">mActivityThread</span><span class="o">,</span> <span class="k">this</span><span class="o">);</span>
<span class="c1">// The network security config needs to be aware of multiple</span>
<span class="c1">// applications in the same process to handle discrepancies</span>
<span class="nc">NetworkSecurityConfigProvider</span><span class="o">.</span><span class="na">handleNewApplication</span><span class="o">(</span><span class="n">appContext</span><span class="o">);</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">mActivityThread</span><span class="o">.</span><span class="na">mInstrumentation</span><span class="o">.</span><span class="na">newApplication</span><span class="o">(</span>
<span class="n">cl</span><span class="o">,</span> <span class="n">appClass</span><span class="o">,</span> <span class="n">appContext</span><span class="o">);</span>
<span class="n">appContext</span><span class="o">.</span><span class="na">setOuterContext</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="n">mActivityThread</span><span class="o">.</span><span class="na">mAllApplications</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="n">mApplication</span> <span class="o">=</span> <span class="n">app</span><span class="o">;</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">instrumentation</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">instrumentation</span><span class="o">.</span><span class="na">callApplicationOnCreate</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">TRACE_TAG_ACTIVITY_MANAGER</span><span class="o">);</span>
<span class="k">return</span> <span class="n">app</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>如果 Application 对象依然存在则直接返回当前对象,否则会通过 Instrumentation(ActivityThread中的成员变量 mInstrumentation,而非参数传递进来的) 来新建一个 Application:</p>
<blockquote>
<p><em>frameworks/base/core/java/android/app/Instrumentation.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="nc">Application</span> <span class="nf">newApplication</span><span class="o">(</span><span class="nc">ClassLoader</span> <span class="n">cl</span><span class="o">,</span> <span class="nc">String</span> <span class="n">className</span><span class="o">,</span> <span class="nc">Context</span> <span class="n">context</span><span class="o">)</span>
<span class="kd">throws</span> <span class="nc">InstantiationException</span><span class="o">,</span> <span class="nc">IllegalAccessException</span><span class="o">,</span>
<span class="nc">ClassNotFoundException</span> <span class="o">{</span>
<span class="nc">Application</span> <span class="n">app</span> <span class="o">=</span> <span class="n">getFactory</span><span class="o">(</span><span class="n">context</span><span class="o">.</span><span class="na">getPackageName</span><span class="o">())</span>
<span class="o">.</span><span class="na">instantiateApplication</span><span class="o">(</span><span class="n">cl</span><span class="o">,</span> <span class="n">className</span><span class="o">);</span>
<span class="n">app</span><span class="o">.</span><span class="na">attach</span><span class="o">(</span><span class="n">context</span><span class="o">);</span>
<span class="k">return</span> <span class="n">app</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nd">@NonNull</span> <span class="nc">Application</span> <span class="nf">instantiateApplication</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="nc">ClassLoader</span> <span class="n">cl</span><span class="o">,</span>
<span class="nd">@NonNull</span> <span class="nc">String</span> <span class="n">className</span><span class="o">)</span>
<span class="kd">throws</span> <span class="nc">InstantiationException</span><span class="o">,</span> <span class="nc">IllegalAccessException</span><span class="o">,</span> <span class="nc">ClassNotFoundException</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">(</span><span class="nc">Application</span><span class="o">)</span> <span class="n">cl</span><span class="o">.</span><span class="na">loadClass</span><span class="o">(</span><span class="n">className</span><span class="o">).</span><span class="na">newInstance</span><span class="o">();</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>可以看到,最终是通过反射生成一个全新的 Application 对象并返回给上层,并执行了它的 <code class="language-plaintext highlighter-rouge">onCreate</code> 方法。至此,Application 创建并启动完毕。</p>
<h3 id="继续启动-activity">继续启动 Activity</h3>
<p>仔细想一下,之前我们分析 Launcher 进程创建过程中的时候,它会提前创建一个 ActivityRecord 对象并置于栈顶,如果当前进程已创建,则直接执行 realStartActivityLocked 来真正启动一个 Activity;如果进程还没有创建,则先创建进程。我们上面分析了一大通不也正是研究了进程还没有创建的情况吗。既然我们后来创建了一个新的 Application,那是不是应该继续之前未完成的使命呢?也就是将先前打断的 Activity 启动的工作继续执行起来。Android 系统不可能连这个问题都考虑不到对吧,所以 Application 创建完毕后应该会继续执行启动 Activity 的逻辑!</p>
<p>我们回到之前的 ActivityManagerService 中查看 <code class="language-plaintext highlighter-rouge">attachApplicationLocked</code>:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
</pre></td><td class="rouge-code"><pre><span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">attachApplicationLocked</span><span class="o">(</span><span class="nd">@NonNull</span> <span class="nc">IApplicationThread</span> <span class="n">thread</span><span class="o">,</span>
<span class="kt">int</span> <span class="n">pid</span><span class="o">,</span> <span class="kt">int</span> <span class="n">callingUid</span><span class="o">,</span> <span class="kt">long</span> <span class="n">startSeq</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">try</span> <span class="o">{</span>
<span class="o">...</span>
<span class="nc">ApplicationInfo</span> <span class="n">appInfo</span> <span class="o">=</span> <span class="n">instr</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">instr</span><span class="o">.</span><span class="na">mTargetInfo</span> <span class="o">:</span> <span class="n">app</span><span class="o">.</span><span class="na">info</span><span class="o">;</span>
<span class="n">app</span><span class="o">.</span><span class="na">setCompat</span><span class="o">(</span><span class="n">compatibilityInfoForPackage</span><span class="o">(</span><span class="n">appInfo</span><span class="o">));</span>
<span class="k">if</span> <span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPoint</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// This is an isolated process which should just call an entry point instead of</span>
<span class="c1">// being bound to an application.</span>
<span class="n">thread</span><span class="o">.</span><span class="na">runIsolatedEntryPoint</span><span class="o">(</span>
<span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPoint</span><span class="o">(),</span> <span class="n">app</span><span class="o">.</span><span class="na">getIsolatedEntryPointArgs</span><span class="o">());</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">instr2</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">thread</span><span class="o">.</span><span class="na">bindApplication</span><span class="o">(</span><span class="n">processName</span><span class="o">,</span> <span class="n">appInfo</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">sdkSandboxClientAppVolumeUuid</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">sdkSandboxClientAppPackage</span><span class="o">,</span>
<span class="n">providerList</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">profilerInfo</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="n">testMode</span><span class="o">,</span>
<span class="n">mBinderTransactionTrackingEnabled</span><span class="o">,</span> <span class="n">enableTrackAllocation</span><span class="o">,</span>
<span class="n">isRestrictedBackupMode</span> <span class="o">||</span> <span class="o">!</span><span class="n">normalMode</span><span class="o">,</span> <span class="n">app</span><span class="o">.</span><span class="na">isPersistent</span><span class="o">(),</span>
<span class="k">new</span> <span class="nf">Configuration</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getWindowProcessController</span><span class="o">().</span><span class="na">getConfiguration</span><span class="o">()),</span>
<span class="n">app</span><span class="o">.</span><span class="na">getCompat</span><span class="o">(),</span> <span class="n">getCommonServicesLocked</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">isolated</span><span class="o">),</span>
<span class="n">mCoreSettingsObserver</span><span class="o">.</span><span class="na">getCoreSettingsLocked</span><span class="o">(),</span>
<span class="n">buildSerial</span><span class="o">,</span> <span class="n">autofillOptions</span><span class="o">,</span> <span class="n">contentCaptureOptions</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getDisabledCompatChanges</span><span class="o">(),</span> <span class="n">serializedSystemFontMap</span><span class="o">,</span>
<span class="n">app</span><span class="o">.</span><span class="na">getStartElapsedTime</span><span class="o">(),</span> <span class="n">app</span><span class="o">.</span><span class="na">getStartUptime</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="c1">// Make app active after binding application or client may be running requests (e.g</span>
<span class="c1">// starting activities) before it is ready.</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mProcLock</span><span class="o">)</span> <span class="o">{</span>
<span class="n">app</span><span class="o">.</span><span class="na">makeActive</span><span class="o">(</span><span class="n">thread</span><span class="o">,</span> <span class="n">mProcessStats</span><span class="o">);</span>
<span class="n">checkTime</span><span class="o">(</span><span class="n">startTime</span><span class="o">,</span> <span class="s">"attachApplicationLocked: immediately after bindApplication"</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="n">didSomething</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="c1">// See if the top visible activity is waiting to run in this process...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">normalMode</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">didSomething</span> <span class="o">=</span> <span class="n">mAtmInternal</span><span class="o">.</span><span class="na">attachApplication</span><span class="o">(</span><span class="n">app</span><span class="o">.</span><span class="na">getWindowProcessController</span><span class="o">());</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">wtf</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception thrown launching activities in "</span> <span class="o">+</span> <span class="n">app</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="n">badApp</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// Find any services that should be running in this process...</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">badApp</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">didSomething</span> <span class="o">|=</span> <span class="n">mServices</span><span class="o">.</span><span class="na">attachApplicationLocked</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="n">processName</span><span class="o">);</span>
<span class="n">checkTime</span><span class="o">(</span><span class="n">startTime</span><span class="o">,</span> <span class="s">"attachApplicationLocked: after mServices.attachApplicationLocked"</span><span class="o">);</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">wtf</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception thrown starting services in "</span> <span class="o">+</span> <span class="n">app</span><span class="o">,</span> <span class="n">e</span><span class="o">);</span>
<span class="n">badApp</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="k">return</span> <span class="kc">true</span><span class="o">;</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>可以看到,在成功创建和绑定 Application 之后,又继续执行了<code class="language-plaintext highlighter-rouge">ActivityTaskManagerInternal#attachApplication</code>,它又做了什么事情呢?:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">attachApplication</span><span class="o">(</span><span class="nc">WindowProcessController</span> <span class="n">wpc</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">RemoteException</span> <span class="o">{</span>
<span class="kd">synchronized</span> <span class="o">(</span><span class="n">mGlobalLockWithoutBoost</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="nc">Trace</span><span class="o">.</span><span class="na">isTagEnabled</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">))</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceBegin</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">,</span> <span class="s">"attachApplication:"</span> <span class="o">+</span> <span class="n">wpc</span><span class="o">.</span><span class="na">mName</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">mRootWindowContainer</span><span class="o">.</span><span class="na">attachApplication</span><span class="o">(</span><span class="n">wpc</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="nc">Trace</span><span class="o">.</span><span class="na">traceEnd</span><span class="o">(</span><span class="no">TRACE_TAG_WINDOW_MANAGER</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>继续跟进到 <code class="language-plaintext highlighter-rouge">RootWindowContainer#attachApplication</code>:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</pre></td><td class="rouge-code"><pre><span class="kt">boolean</span> <span class="nf">attachApplication</span><span class="o">(</span><span class="nc">WindowProcessController</span> <span class="n">app</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">RemoteException</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">mAttachApplicationHelper</span><span class="o">.</span><span class="na">process</span><span class="o">(</span><span class="n">app</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mAttachApplicationHelper</span><span class="o">.</span><span class="na">reset</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kt">boolean</span> <span class="nf">process</span><span class="o">(</span><span class="nc">WindowProcessController</span> <span class="n">app</span><span class="o">)</span> <span class="kd">throws</span> <span class="nc">RemoteException</span> <span class="o">{</span>
<span class="n">mApp</span> <span class="o">=</span> <span class="n">app</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">displayNdx</span> <span class="o">=</span> <span class="n">getChildCount</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">displayNdx</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">displayNdx</span><span class="o">)</span> <span class="o">{</span>
<span class="n">getChildAt</span><span class="o">(</span><span class="n">displayNdx</span><span class="o">).</span><span class="na">forAllRootTasks</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mRemoteException</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="n">mRemoteException</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">mHasActivityStarted</span><span class="o">)</span> <span class="o">{</span>
<span class="n">ensureActivitiesVisible</span><span class="o">(</span><span class="kc">null</span> <span class="cm">/* starting */</span><span class="o">,</span> <span class="mi">0</span> <span class="cm">/* configChanges */</span><span class="o">,</span>
<span class="kc">false</span> <span class="cm">/* preserveWindows */</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">mHasActivityStarted</span><span class="o">;</span>
<span class="o">}</span>
<span class="kt">void</span> <span class="nf">ensureActivitiesVisible</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">notifyClients</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">inActivityVisibilityUpdate</span><span class="o">()</span>
<span class="o">||</span> <span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">isRootVisibilityUpdateDeferred</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">// Don't do recursive work.</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">beginActivityVisibilityUpdate</span><span class="o">();</span>
<span class="c1">// First the front root tasks. In case any are not fullscreen and are in front of home.</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">displayNdx</span> <span class="o">=</span> <span class="n">getChildCount</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">displayNdx</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">displayNdx</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">DisplayContent</span> <span class="n">display</span> <span class="o">=</span> <span class="n">getChildAt</span><span class="o">(</span><span class="n">displayNdx</span><span class="o">);</span>
<span class="n">display</span><span class="o">.</span><span class="na">ensureActivitiesVisible</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span>
<span class="n">notifyClients</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">endActivityVisibilityUpdate</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>这里是查找 Activity 栈是否存在需要被启动的 Activity,继续跟进 <code class="language-plaintext highlighter-rouge">DisplayContent#ensureActivitiesVisible</code>:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">ensureActivitiesVisible</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">notifyClients</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mInEnsureActivitiesVisible</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Don't do recursive work.</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">mInEnsureActivitiesVisible</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="n">mAtmService</span><span class="o">.</span><span class="na">mTaskSupervisor</span><span class="o">.</span><span class="na">beginActivityVisibilityUpdate</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">forAllRootTasks</span><span class="o">(</span><span class="n">rootTask</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">rootTask</span><span class="o">.</span><span class="na">ensureActivitiesVisible</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span>
<span class="n">notifyClients</span><span class="o">);</span>
<span class="o">});</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mTransitionController</span><span class="o">.</span><span class="na">useShellTransitionsRotation</span><span class="o">()</span>
<span class="o">&&</span> <span class="n">mTransitionController</span><span class="o">.</span><span class="na">isCollecting</span><span class="o">()</span>
<span class="o">&&</span> <span class="n">mWallpaperController</span><span class="o">.</span><span class="na">getWallpaperTarget</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Also update wallpapers so that their requestedVisibility immediately reflects</span>
<span class="c1">// the changes to activity visibility.</span>
<span class="c1">// TODO(b/206005136): Move visibleRequested logic up to WindowToken.</span>
<span class="n">mWallpaperController</span><span class="o">.</span><span class="na">adjustWallpaperWindows</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mAtmService</span><span class="o">.</span><span class="na">mTaskSupervisor</span><span class="o">.</span><span class="na">endActivityVisibilityUpdate</span><span class="o">();</span>
<span class="n">mInEnsureActivitiesVisible</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>接着跟进 <code class="language-plaintext highlighter-rouge">Task#ensureActivitiesVisible</code>:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/Task.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
</pre></td><td class="rouge-code"><pre><span class="cm">/**
* Make sure that all activities that need to be visible in the root task (that is, they
* currently can be seen by the user) actually are and update their configuration.
* @param starting The top most activity in the task.
* The activity is either starting or resuming.
* Caller should ensure starting activity is visible.
* @param preserveWindows Flag indicating whether windows should be preserved when updating
* configuration in {@link EnsureActivitiesVisibleHelper}.
* @param configChanges Parts of the configuration that changed for this activity for evaluating
* if the screen should be frozen as part of
* {@link EnsureActivitiesVisibleHelper}.
*
*/</span>
<span class="kt">void</span> <span class="nf">ensureActivitiesVisible</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">)</span> <span class="o">{</span>
<span class="n">ensureActivitiesVisible</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="kc">true</span> <span class="cm">/* notifyClients */</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**
* Ensure visibility with an option to also update the configuration of visible activities.
* @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
* @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
* @param starting The top most activity in the task.
* The activity is either starting or resuming.
* Caller should ensure starting activity is visible.
* @param notifyClients Flag indicating whether the visibility updates should be sent to the
* clients in {@link EnsureActivitiesVisibleHelper}.
* @param preserveWindows Flag indicating whether windows should be preserved when updating
* configuration in {@link EnsureActivitiesVisibleHelper}.
* @param configChanges Parts of the configuration that changed for this activity for evaluating
* if the screen should be frozen as part of
* {@link EnsureActivitiesVisibleHelper}.
*/</span>
<span class="c1">// TODO: Should be re-worked based on the fact that each task as a root task in most cases.</span>
<span class="kt">void</span> <span class="nf">ensureActivitiesVisible</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">notifyClients</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">beginActivityVisibilityUpdate</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">forAllLeafTasks</span><span class="o">(</span><span class="n">task</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">task</span><span class="o">.</span><span class="na">updateActivityVisibilities</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span>
<span class="n">notifyClients</span><span class="o">);</span>
<span class="o">},</span> <span class="kc">true</span> <span class="cm">/* traverseTopToBottom */</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">mTranslucentActivityWaiting</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span>
<span class="n">mUndrawnActivitiesBelowTopTranslucent</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">// Nothing is getting drawn or everything was already visible, don't wait for</span>
<span class="c1">// timeout.</span>
<span class="n">notifyActivityDrawnLocked</span><span class="o">(</span><span class="kc">null</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">endActivityVisibilityUpdate</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">final</span> <span class="kt">void</span> <span class="nf">updateActivityVisibilities</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">notifyClients</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">beginActivityVisibilityUpdate</span><span class="o">();</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">mEnsureActivitiesVisibleHelper</span><span class="o">.</span><span class="na">process</span><span class="o">(</span>
<span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="n">notifyClients</span><span class="o">);</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">mTaskSupervisor</span><span class="o">.</span><span class="na">endActivityVisibilityUpdate</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>进入 <code class="language-plaintext highlighter-rouge">EnsureActivityVisibilities</code> :</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">process</span><span class="o">(</span><span class="nd">@Nullable</span> <span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">preserveWindows</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">notifyClients</span><span class="o">)</span> <span class="o">{</span>
<span class="n">reset</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span> <span class="n">preserveWindows</span><span class="o">,</span> <span class="n">notifyClients</span><span class="o">);</span>
<span class="o">...</span>
<span class="c1">// We should not resume activities that being launched behind because these</span>
<span class="c1">// activities are actually behind other fullscreen activities, but still required</span>
<span class="c1">// to be visible (such as performing Recents animation).</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">resumeTopActivity</span> <span class="o">=</span> <span class="n">mTopRunningActivity</span> <span class="o">!=</span> <span class="kc">null</span>
<span class="o">&&</span> <span class="o">!</span><span class="n">mTopRunningActivity</span><span class="o">.</span><span class="na">mLaunchTaskBehind</span>
<span class="o">&&</span> <span class="n">mTaskFragment</span><span class="o">.</span><span class="na">canBeResumed</span><span class="o">(</span><span class="n">starting</span><span class="o">)</span>
<span class="o">&&</span> <span class="o">(</span><span class="n">starting</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="o">!</span><span class="n">starting</span><span class="o">.</span><span class="na">isDescendantOf</span><span class="o">(</span><span class="n">mTaskFragment</span><span class="o">));</span>
<span class="nc">ArrayList</span><span class="o"><</span><span class="nc">TaskFragment</span><span class="o">></span> <span class="n">adjacentTaskFragments</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">mTaskFragment</span><span class="o">.</span><span class="na">mChildren</span><span class="o">.</span><span class="na">size</span><span class="o">()</span> <span class="o">-</span> <span class="mi">1</span><span class="o">;</span> <span class="n">i</span> <span class="o">>=</span> <span class="mi">0</span><span class="o">;</span> <span class="o">--</span><span class="n">i</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="nc">WindowContainer</span> <span class="n">child</span> <span class="o">=</span> <span class="n">mTaskFragment</span><span class="o">.</span><span class="na">mChildren</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">);</span>
<span class="kd">final</span> <span class="nc">TaskFragment</span> <span class="n">childTaskFragment</span> <span class="o">=</span> <span class="n">child</span><span class="o">.</span><span class="na">asTaskFragment</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">childTaskFragment</span> <span class="o">!=</span> <span class="kc">null</span>
<span class="o">&&</span> <span class="n">childTaskFragment</span><span class="o">.</span><span class="na">getTopNonFinishingActivity</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">childTaskFragment</span><span class="o">.</span><span class="na">updateActivityVisibilities</span><span class="o">(</span><span class="n">starting</span><span class="o">,</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="n">preserveWindows</span><span class="o">,</span> <span class="n">notifyClients</span><span class="o">);</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">child</span><span class="o">.</span><span class="na">asActivityRecord</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">setActivityVisibilityState</span><span class="o">(</span><span class="n">child</span><span class="o">.</span><span class="na">asActivityRecord</span><span class="o">(),</span> <span class="n">starting</span><span class="o">,</span> <span class="n">resumeTopActivity</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">setActivityVisibilityState</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">,</span> <span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">resumeTopActivity</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">reallyVisible</span><span class="o">)</span> <span class="o">{</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">r</span><span class="o">.</span><span class="na">attachedToProcess</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">// 需要关联到具体的进程并启动activity</span>
<span class="n">makeVisibleAndRestartIfNeeded</span><span class="o">(</span><span class="n">mStarting</span><span class="o">,</span> <span class="n">mConfigChanges</span><span class="o">,</span> <span class="n">isTop</span><span class="o">,</span>
<span class="n">resumeTopActivity</span> <span class="o">&&</span> <span class="n">isTop</span><span class="o">,</span> <span class="n">r</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">r</span><span class="o">.</span><span class="na">isVisibleRequested</span><span class="o">())</span> <span class="o">{</span>
<span class="c1">// If this activity is already visible, then there is nothing to do here.</span>
<span class="o">...</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">r</span><span class="o">.</span><span class="na">makeVisibleIfNeeded</span><span class="o">(</span><span class="n">mStarting</span><span class="o">,</span> <span class="n">mNotifyClients</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// Aggregate current change flags.</span>
<span class="n">mConfigChanges</span> <span class="o">|=</span> <span class="n">r</span><span class="o">.</span><span class="na">configChangeFlags</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="o">...</span>
<span class="n">r</span><span class="o">.</span><span class="na">makeInvisible</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">...</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">makeVisibleAndRestartIfNeeded</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">starting</span><span class="o">,</span> <span class="kt">int</span> <span class="n">configChanges</span><span class="o">,</span>
<span class="kt">boolean</span> <span class="n">isTop</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">andResume</span><span class="o">,</span> <span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// We need to make sure the app is running if it's the top, or it is just made visible from</span>
<span class="c1">// invisible. If the app is already visible, it must have died while it was visible. In this</span>
<span class="c1">// case, we'll show the dead window but will not restart the app. Otherwise we could end up</span>
<span class="c1">// thrashing.</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">isTop</span> <span class="o">&&</span> <span class="n">r</span><span class="o">.</span><span class="na">isVisibleRequested</span><span class="o">()</span> <span class="o">&&</span> <span class="o">!</span><span class="n">r</span><span class="o">.</span><span class="na">isState</span><span class="o">(</span><span class="no">INITIALIZING</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">// This activity needs to be visible, but isn't even running...</span>
<span class="c1">// get it started and resume if no other root task in this root task is resumed.</span>
<span class="o">...</span>
<span class="k">if</span> <span class="o">(</span><span class="n">r</span> <span class="o">!=</span> <span class="n">starting</span><span class="o">)</span> <span class="o">{</span>
<span class="n">mTaskFragment</span><span class="o">.</span><span class="na">mTaskSupervisor</span><span class="o">.</span><span class="na">startSpecificActivity</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">andResume</span><span class="o">,</span>
<span class="kc">true</span> <span class="cm">/* checkConfig */</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>看到这里,我们可以大胆猜测 Activity 即使已经存在,但尚未显示,也没有关联到具体的进程。如果顶部没有其他的 Activity,我们可以尝试启动这个 Activity:</p>
<blockquote>
<p><em>frameworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java</em></p>
</blockquote>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
</pre></td><td class="rouge-code"><pre><span class="kt">void</span> <span class="nf">startSpecificActivity</span><span class="o">(</span><span class="nc">ActivityRecord</span> <span class="n">r</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">andResume</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">checkConfig</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Is this activity's application already running?</span>
<span class="kd">final</span> <span class="nc">WindowProcessController</span> <span class="n">wpc</span> <span class="o">=</span>
<span class="n">mService</span><span class="o">.</span><span class="na">getProcessController</span><span class="o">(</span><span class="n">r</span><span class="o">.</span><span class="na">processName</span><span class="o">,</span> <span class="n">r</span><span class="o">.</span><span class="na">info</span><span class="o">.</span><span class="na">applicationInfo</span><span class="o">.</span><span class="na">uid</span><span class="o">);</span>
<span class="kt">boolean</span> <span class="n">knownToBeDead</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">wpc</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">wpc</span><span class="o">.</span><span class="na">hasThread</span><span class="o">())</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">realStartActivityLocked</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">wpc</span><span class="o">,</span> <span class="n">andResume</span><span class="o">,</span> <span class="n">checkConfig</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="nc">RemoteException</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">Slog</span><span class="o">.</span><span class="na">w</span><span class="o">(</span><span class="no">TAG</span><span class="o">,</span> <span class="s">"Exception when starting activity "</span>
<span class="o">+</span> <span class="n">r</span><span class="o">.</span><span class="na">intent</span><span class="o">.</span><span class="na">getComponent</span><span class="o">().</span><span class="na">flattenToShortString</span><span class="o">(),</span> <span class="n">e</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">// If a dead object exception was thrown -- fall through to</span>
<span class="c1">// restart the application.</span>
<span class="n">knownToBeDead</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="c1">// Remove the process record so it won't be considered as alive.</span>
<span class="n">mService</span><span class="o">.</span><span class="na">mProcessNames</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">wpc</span><span class="o">.</span><span class="na">mName</span><span class="o">,</span> <span class="n">wpc</span><span class="o">.</span><span class="na">mUid</span><span class="o">);</span>
<span class="n">mService</span><span class="o">.</span><span class="na">mProcessMap</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">wpc</span><span class="o">.</span><span class="na">getPid</span><span class="o">());</span>
<span class="o">}</span>
<span class="n">r</span><span class="o">.</span><span class="na">notifyUnknownVisibilityLaunchedForKeyguardTransition</span><span class="o">();</span>
<span class="kd">final</span> <span class="kt">boolean</span> <span class="n">isTop</span> <span class="o">=</span> <span class="n">andResume</span> <span class="o">&&</span> <span class="n">r</span><span class="o">.</span><span class="na">isTopRunningActivity</span><span class="o">();</span>
<span class="n">mService</span><span class="o">.</span><span class="na">startProcessAsync</span><span class="o">(</span><span class="n">r</span><span class="o">,</span> <span class="n">knownToBeDead</span><span class="o">,</span> <span class="n">isTop</span><span class="o">,</span>
<span class="n">isTop</span> <span class="o">?</span> <span class="nc">HostingRecord</span><span class="o">.</span><span class="na">HOSTING_TYPE_TOP_ACTIVITY</span>
<span class="o">:</span> <span class="nc">HostingRecord</span><span class="o">.</span><span class="na">HOSTING_TYPE_ACTIVITY</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table></code></pre></div></div>
<p>Wonderful!这代码是不是有点熟悉,没错,我们再次回到了这个分叉路口:</p>
<ul>
<li>如果 Activity 的进程已经启动,则直接执行 <code class="language-plaintext highlighter-rouge">realStartActivityLocked</code> 来启动 Activity;</li>
<li>如果 Activity 的进程尚未启动,那么需要先执行 <code class="language-plaintext highlighter-rouge">ActivityTaskManagerService#startProcessAsync</code> 创建进程。</li>
</ul>
<p><strong>只不过这次我们已经拥有了一个正在运行的进程,所以这一次将会执行到 realStartActivityLocked 来启动一个 Activity。</strong></p>
<h3 id="总结">总结</h3>
<p>Android 中在 system_server 进程启动 Launcher 进程主要有以下几个步骤:</p>
<ol>
<li>准备参数信息:AMS 执行 systemReady,接着组装 homeIntent 和 ActivityRecord。</li>
<li>判断是否需要新建进程:如果当前存在进程,则直接启动 Activity,否则先创建和启动进程。</li>
<li>等待创建请求:Zygote 进程会在启动后等待新的应用程序进程的创建请求。</li>
<li>接收创建请求:当有新的应用程序进程的创建请求到达时,Zygote 进程会接收该请求,并根据该请求创建一个新的进程。</li>
<li>复制进程:为了快速创建新的进程,Zygote 进程会通过复制自身进程并清除一些状态来创建一个新的应用程序进程。这个过程是通过使用类似于 Unix 的 fork 系统调用实现的。</li>
<li>初始化应用程序进程:新的应用程序进程会继承 Zygote 进程的一些特性,例如 Java 虚拟机实例、类和资源等。Zygote 进程会对新进程进行一些初始化工作,例如为新进程设置一些系统属性、启动主线程等。</li>
<li>加载应用程序代码:新的应用程序进程会在启动时加载应用程序的代码,并开始执行应用程序的入口函数。</li>
<li>启动 Launcher Activity:当进程和 Application 创建完毕后,如果存在未启动的 Activity,则前往创建执行启动。</li>
</ol>
<p>关于 Activity 的启动过程将在下一章节来剖析,到时也会附上整个 APP 启动过程关键节点流程图。</p>
<h3 id="相关面试题">相关面试题</h3>
<ul>
<li>应用进程的孵化过程?</li>
<li>Android 创建进程时的 USAP 机制是什么?</li>
<li>为什么 Android 进程的 <code class="language-plaintext highlighter-rouge">fork()</code> 会返回两次?</li>
<li>Android 系统的 Activity Task 管理机制?</li>
</ul>
<h3 id="相关参考">相关参考</h3>
<ul>
<li>https://juejin.cn/post/6978743408756162590</li>
<li>https://blog.csdn.net/zhuzp_blog/article/details/120894309</li>
<li>https://blog.csdn.net/qq_34512207/article/details/113725772</li>
</ul>