Android ActivityManagerService(AMS)的启动分析

版权声明:本文为博主原创文章,未经博主允许不得转载。
Android中的AMS想必是做android开发的工程师耳熟能详的系统级别的服务,但是它又是如此地庞大(单单ActivityManagerService.java文件就2W+行代码),因此我们在学习它的时候总是不能找到实际的主线,很是混乱。这里我会连续写几篇文章从它的启动过程,主要业务逻辑,和别的模块之间的互操作逻辑等角度来向大家简单介绍一下它。这里我只能是抛砖引玉,简单介绍,不会面面俱到,因为AMS的代码量确实比较大,如果向大家一一道来,想必大家一定会厌烦而且学习效果不好。希望大家在阅读本文的时候,同时查看android相关源码,自己动手,自己思考,你会有很大的提高的!
注:本文的所有的分析全部基于google最新的android 6.0.0进行的,6.0之前的版本可能有很多地方不一致,请知悉。
好了下面,我们就开始从头分析一下AMS,首先从AMS的启动流程开始。
AMS的启动过程
Android中的很多使用java语言编写的service都是在SystemServer中启动的,SystemServer是由系统启动的时候zygote启动的第一个java程序。AMS的是在SystemServer中的startBootstrapServices方法中启动的,android系统中的很多核心关键服务都是在这个函数中启动的,这个方法中有这么一段代码:
startBootstrapServices@SystemServer.java:
<code class="hljs avrasm has-numbering">// Activity manager runs the show. mActivityManagerService = mSystemServiceManager<span class="hljs-preprocessor">.startService</span>( ActivityManagerService<span class="hljs-preprocessor">.Lifecycle</span><span class="hljs-preprocessor">.class</span>)<span class="hljs-preprocessor">.getService</span>()<span class="hljs-comment">;</span> mActivityManagerService<span class="hljs-preprocessor">.setSystemServiceManager</span>(mSystemServiceManager)<span class="hljs-comment">;</span> mActivityManagerService<span class="hljs-preprocessor">.setInstaller</span>(installer)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>
这里调用了mSystemServiceManager对象的startService启动了AMS,注意这里给出的参数是ActivityManagerService.Lifecycle.class,在进一步分析startService之前,我们需要看一下这个类:
Lifecycle@ActivityManagerService.java
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Lifecycle</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">SystemService</span> {</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ActivityManagerService mService; <span class="hljs-keyword">public</span> <span class="hljs-title">Lifecycle</span>(Context context) { <span class="hljs-keyword">super</span>(context); mService = <span class="hljs-keyword">new</span> ActivityManagerService(context); } <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() { mService.start(); } <span class="hljs-keyword">public</span> ActivityManagerService <span class="hljs-title">getService</span>() { <span class="hljs-keyword">return</span> mService; } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul>
从这个类的名字就可以看出来,这是一个关于AMS的生命周期的内部类,构造器中实例化了一个AMS的对象。同时这个类继承自SystemService类(这是所有系统级别服务都应该继承的父类,主要定义了一些关于生命周期和上下文的接口),并且复写了onStart方法:
onStart@SystemService.java
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * Called when the dependencies listed in the<span class="hljs-javadoctag"> @Service</span> class-annotation are available * and after the chosen start phase. * When this method returns, the service should be published. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
可以看出来,这是当服务启动的时候回调的方法,具体再哪里调用,我们后面会分析。弄清楚了Lifecycle类之后,我们现在可以来分析mSystemServiceManager对象的startService方法,mSystemServiceManager是SystemServiceManager类的一个对象,下面是startService方法:
startService@SystemServiceManager.java
<code class="hljs scala has-numbering"><span class="hljs-javadoc">/** * Creates and starts a system service. The class must be a subclass of * {<span class="hljs-javadoctag">@link</span> com.android.server.SystemService}. * * <span class="hljs-javadoctag">@param</span> serviceClass A Java class that implements the SystemService interface. * <span class="hljs-javadoctag">@return</span> The service instance, never null. * <span class="hljs-javadoctag">@throws</span> RuntimeException if the service fails to start. */</span> <span class="hljs-annotation">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>) public <T <span class="hljs-keyword">extends</span> SystemService> T startService(Class<T> serviceClass) { <span class="hljs-keyword">final</span> String name = serviceClass.getName(); Slog.i(TAG, <span class="hljs-string">"Starting "</span> + name); <span class="hljs-comment">// Create the service.</span> <span class="hljs-keyword">if</span> (!SystemService.<span class="hljs-keyword">class</span>.isAssignableFrom(serviceClass)) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create "</span> + name + <span class="hljs-string">": service must extend "</span> + SystemService.<span class="hljs-keyword">class</span>.getName()); } <span class="hljs-keyword">final</span> T service; <span class="hljs-keyword">try</span> { Constructor<T> constructor = serviceClass.getConstructor(Context.<span class="hljs-keyword">class</span>); service = constructor.newInstance(mContext); } <span class="hljs-keyword">catch</span> (InstantiationException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create service "</span> + name + <span class="hljs-string">": service could not be instantiated"</span>, ex); } <span class="hljs-keyword">catch</span> (IllegalAccessException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create service "</span> + name + <span class="hljs-string">": service must have a public constructor with a Context argument"</span>, ex); } <span class="hljs-keyword">catch</span> (NoSuchMethodException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create service "</span> + name + <span class="hljs-string">": service must have a public constructor with a Context argument"</span>, ex); } <span class="hljs-keyword">catch</span> (InvocationTargetException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to create service "</span> + name + <span class="hljs-string">": service constructor threw an exception"</span>, ex); } <span class="hljs-comment">// Register it.</span> mServices.add(service); <span class="hljs-comment">// Start it.</span> <span class="hljs-keyword">try</span> { service.onStart(); } <span class="hljs-keyword">catch</span> (RuntimeException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to start service "</span> + name + <span class="hljs-string">": onStart threw an exception"</span>, ex); } <span class="hljs-keyword">return</span> service; }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li></ul>
这里我们需要说明一下,在上面调用这个方法的时候,我们传递进来的参数是一个类,而不是这个类的对象,也就是说我们仅仅给出了类型并没有进行实例化!因此这里的方法参数是一个泛型。在这个方法中我们首先获得传递进来类的名字,然后进行一个很重要的操作,那就是java类型判断,使用isAssignableFrom完成,isAssignableFrom和instanceof类似,只是instanceof针对类的对象进行判断,而isAssignableFrom针对类进行判断,也就是说这是在只有类而没有类的对象的时候进行判断类之间的继承关系的方式。更多关于isAssignableFrom和instanceof的区别请看博客:
http://blog.youkuaiyun.com/kjfcpua/article/details/7045207
我们这里判断了传递进来的类是不是SystemService类的子类,如果不是的话直接刨除运行时异常立即停止运行,因为服务必须继承自SystemService类!代码中的异常信息也可以看到这一点。接下来,就获得类的构造器,并且实例化一个对象:
<code class="hljs delphi has-numbering"><span class="hljs-comment">// 获得构造器</span> <span class="hljs-function"><span class="hljs-keyword">Constructor</span><<span class="hljs-title">T</span>> <span class="hljs-title">constructor</span> = <span class="hljs-title">serviceClass</span>.<span class="hljs-title">getConstructor</span><span class="hljs-params">(Context.<span class="hljs-keyword">class</span>)</span>;</span> <span class="hljs-comment">// 实例化一个对象</span> service = <span class="hljs-function"><span class="hljs-keyword">constructor</span>.<span class="hljs-title">newInstance</span><span class="hljs-params">(mContext)</span>;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
现在我们需要看一下实例化的时候做了什么工作,下面是Lifecycle类的构造器:
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-title">Lifecycle</span>(Context context) { <span class="hljs-keyword">super</span>(context); mService = <span class="hljs-keyword">new</span> ActivityManagerService(context); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
我们可以看到,这里实例化了一个ActivityManagerService类的对象,我们看一下ActivityManagerService类的构造器:
<code class="hljs cs has-numbering"><span class="hljs-comment">// Note: This method is invoked on the main thread but may need to attach various</span> <span class="hljs-comment">// handlers to other threads. So take care to be explicit about the looper.</span> <span class="hljs-keyword">public</span> <span class="hljs-title">ActivityManagerService</span>(Context systemContext) { mContext = systemContext; mFactoryTest = FactoryTest.getMode(); <span class="hljs-comment">// 获得当前运行在SystemServer中的ActivityThread对象</span> mSystemThread = ActivityThread.currentActivityThread(); Slog.i(TAG, <span class="hljs-string">"Memory class: "</span> + ActivityManager.staticGetMemoryClass()); <span class="hljs-comment">// 创建用于处理本线程消息的线程和Handler对象,消息处理Handler是MainHandler类</span> mHandlerThread = <span class="hljs-keyword">new</span> ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, <span class="hljs-keyword">false</span> <span class="hljs-comment">/*allowIo*/</span>); mHandlerThread.start(); mHandler = <span class="hljs-keyword">new</span> MainHandler(mHandlerThread.getLooper()); mUiHandler = <span class="hljs-keyword">new</span> UiHandler(); <span class="hljs-comment">// 创建intent广播管理类对象</span> mFgBroadcastQueue = <span class="hljs-keyword">new</span> BroadcastQueue(<span class="hljs-keyword">this</span>, mHandler, <span class="hljs-string">"foreground"</span>, BROADCAST_FG_TIMEOUT, <span class="hljs-keyword">false</span>); mBgBroadcastQueue = <span class="hljs-keyword">new</span> BroadcastQueue(<span class="hljs-keyword">this</span>, mHandler, <span class="hljs-string">"background"</span>, BROADCAST_BG_TIMEOUT, <span class="hljs-keyword">true</span>); mBroadcastQueues[<span class="hljs-number">0</span>] = mFgBroadcastQueue; mBroadcastQueues[<span class="hljs-number">1</span>] = mBgBroadcastQueue; <span class="hljs-comment">// 所有的service的列表对象</span> mServices = <span class="hljs-keyword">new</span> ActiveServices(<span class="hljs-keyword">this</span>); <span class="hljs-comment">// 所有的provider的列表对象</span> mProviderMap = <span class="hljs-keyword">new</span> ProviderMap(<span class="hljs-keyword">this</span>); <span class="hljs-comment">// TODO: Move creation of battery stats service outside of activity manager service.</span> <span class="hljs-comment">// 获得系统的/data/system目录,并且这个目录将用于创建MainHandler</span> File dataDir = Environment.getDataDirectory(); File systemDir = <span class="hljs-keyword">new</span> File(dataDir, <span class="hljs-string">"system"</span>); systemDir.mkdirs(); <span class="hljs-comment">// 创建Battery服务对象</span> mBatteryStatsService = <span class="hljs-keyword">new</span> BatteryStatsService(systemDir, mHandler); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.scheduleWriteToDisk(); mOnBattery = DEBUG_POWER ? <span class="hljs-keyword">true</span> : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(<span class="hljs-keyword">this</span>); mProcessStats = <span class="hljs-keyword">new</span> ProcessStatsService(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">new</span> File(systemDir, <span class="hljs-string">"procstats"</span>)); mAppOpsService = <span class="hljs-keyword">new</span> AppOpsService(<span class="hljs-keyword">new</span> File(systemDir, <span class="hljs-string">"appops.xml"</span>), mHandler); <span class="hljs-comment">// 打开/data/system/urigrants.xml,管理URI权限(与content provid读写有关)</span> <span class="hljs-comment">// 更多关于URI权限可以查看: https://developer.android.com/guide/topics/security/permissions.html#uri</span> mGrantFile = <span class="hljs-keyword">new</span> AtomicFile(<span class="hljs-keyword">new</span> File(systemDir, <span class="hljs-string">"urigrants.xml"</span>)); <span class="hljs-comment">// User 0 is the first and only user that runs at boot.</span> mStartedUsers.put(UserHandle.USER_OWNER, <span class="hljs-keyword">new</span> UserState(UserHandle.OWNER, <span class="hljs-keyword">true</span>)); mUserLru.add(UserHandle.USER_OWNER); updateStartedUserArrayLocked(); <span class="hljs-comment">// 获得opengl es的版本信息</span> GL_ES_VERSION = SystemProperties.getInt(<span class="hljs-string">"ro.opengles.version"</span>, ConfigurationInfo.GL_ES_VERSION_UNDEFINED); mTrackingAssociations = <span class="hljs-string">"1"</span>.equals(SystemProperties.<span class="hljs-keyword">get</span>(<span class="hljs-string">"debug.track-associations"</span>)); mConfiguration.setToDefaults(); mConfiguration.setLocale(Locale.getDefault()); mConfigurationSeq = mConfiguration.seq = <span class="hljs-number">1</span>; mProcessCpuTracker.init(); mCompatModePackages = <span class="hljs-keyword">new</span> CompatModePackages(<span class="hljs-keyword">this</span>, systemDir, mHandler); <span class="hljs-comment">// 创建intent防火墙</span> mIntentFirewall = <span class="hljs-keyword">new</span> IntentFirewall(<span class="hljs-keyword">new</span> IntentFirewallInterface(), mHandler); mRecentTasks = <span class="hljs-keyword">new</span> RecentTasks(<span class="hljs-keyword">this</span>); mStackSupervisor = <span class="hljs-keyword">new</span> ActivityStackSupervisor(<span class="hljs-keyword">this</span>, mRecentTasks); mTaskPersister = <span class="hljs-keyword">new</span> TaskPersister(systemDir, mStackSupervisor, mRecentTasks); <span class="hljs-comment">// cpu使用监控线程</span> mProcessCpuThread = <span class="hljs-keyword">new</span> Thread(<span class="hljs-string">"CpuTracker"</span>) { @Override <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() { <span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) { <span class="hljs-keyword">try</span> { <span class="hljs-keyword">try</span> { synchronized(<span class="hljs-keyword">this</span>) { final <span class="hljs-keyword">long</span> now = SystemClock.uptimeMillis(); <span class="hljs-keyword">long</span> nextCpuDelay = (mLastCpuTime.<span class="hljs-keyword">get</span>()+MONITOR_CPU_MAX_TIME)-now; <span class="hljs-keyword">long</span> nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now; <span class="hljs-comment">//Slog.i(TAG, "Cpu delay=" + nextCpuDelay</span> <span class="hljs-comment">// + ", write delay=" + nextWriteDelay);</span> <span class="hljs-keyword">if</span> (nextWriteDelay < nextCpuDelay) { nextCpuDelay = nextWriteDelay; } <span class="hljs-keyword">if</span> (nextCpuDelay > <span class="hljs-number">0</span>) { mProcessCpuMutexFree.<span class="hljs-keyword">set</span>(<span class="hljs-keyword">true</span>); <span class="hljs-keyword">this</span>.wait(nextCpuDelay); } } } <span class="hljs-keyword">catch</span> (InterruptedException e) { } updateCpuStatsNow(); } <span class="hljs-keyword">catch</span> (Exception e) { Slog.e(TAG, <span class="hljs-string">"Unexpected exception collecting process stats"</span>, e); } } } }; <span class="hljs-comment">// 将服务加入看门狗的监控</span> Watchdog.getInstance().addMonitor(<span class="hljs-keyword">this</span>); Watchdog.getInstance().addThread(mHandler); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li><li>77</li><li>78</li><li>79</li><li>80</li><li>81</li><li>82</li><li>83</li><li>84</li><li>85</li><li>86</li><li>87</li><li>88</li><li>89</li><li>90</li><li>91</li><li>92</li><li>93</li><li>94</li><li>95</li><li>96</li><li>97</li><li>98</li><li>99</li><li>100</li><li>101</li><li>102</li><li>103</li><li>104</li><li>105</li><li>106</li><li>107</li><li>108</li><li>109</li><li>110</li></ul>
这个构造器比较长,并且基本都是一些AMS日常工作的初始化,包括创建四大组件的管理对象以及一些内部对象,因此我们这里就不详细分析构造器的工作了,后面分析AMS的服务逻辑的时候我们在来分析对应的初始化工作。这里有一点需要说一下,就是上面的创建intent防火墙部分,所谓intent防火墙是在android4.4.2中引入的一个intent过滤安全机制,在我们使用intent启动activity,service,发送广播的时候都会通过这个机制检查是不是允许执行,只有允许了才能真正执行。更多关于intent防火墙的介绍请看美国Syracuse University的一名研究生的文档(Google在这块基本没有文档,可能是方案还没有成熟。。。。):
http://www.cis.syr.edu/~wedu/android/IntentFirewall/index.html
现在我们只要知道在AMS的构造器中做了这些工作就可以了:
1. 创建一堆类的对象,这些对象对于AMS的日常工作来说是必需的。
2. 初始化battery stats相关服务,AMS除了负责activity的管理工作,还负责battery stats相关的工作
3. 初始化cpu统计相关服务,主要是启动一个线程,轮询处理。为AMS提供有关CPU运行统计方面数据做准备。
最后进行这个方法中最重要的操作,那就是将服务添加到ServiceManager中去,方面别的进程使用Binder查找到这个服务:
<code class="hljs oxygene has-numbering"><span class="hljs-comment">// Register it.</span> mServices.<span class="hljs-keyword">add</span>(service);</code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>
需要注意的是,这里的添加注册服务并不是Binder添加注册服务,我们看一下mServices的类型就知道了:
<code class="hljs java has-numbering"><span class="hljs-comment">// Services that should receive lifecycle events.</span> <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ArrayList<SystemService> mServices = <span class="hljs-keyword">new</span> ArrayList<SystemService>();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>
是的,mServices就是一个列表,这个列表中包含了它启动的所有SystemService类的服务,以便于后面调用它的生命周期方法。
接下来的操作就是回调我们前面提到的onStart方法:
<code class="hljs cs has-numbering"><span class="hljs-comment">// Start it.</span> <span class="hljs-keyword">try</span> { service.onStart(); } <span class="hljs-keyword">catch</span> (RuntimeException ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to start service "</span> + name + <span class="hljs-string">": onStart threw an exception"</span>, ex); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>
这里就回调到了AMS中Lifecycle内部类的onStart方法了,最后就是将实例化的service返回。接下来我们先分析一下Lifecycle的onStart:
<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onStart</span>() { mService.start(); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
我们看到,这里直接调用ActivityManagerService的start方法:
start@ActivityManagerService.java
<code class="hljs avrasm has-numbering">private void start() { Process<span class="hljs-preprocessor">.removeAllProcessGroups</span>()<span class="hljs-comment">;</span> mProcessCpuThread<span class="hljs-preprocessor">.start</span>()<span class="hljs-comment">;</span> mBatteryStatsService<span class="hljs-preprocessor">.publish</span>(mContext)<span class="hljs-comment">;</span> mAppOpsService<span class="hljs-preprocessor">.publish</span>(mContext)<span class="hljs-comment">;</span> Slog<span class="hljs-preprocessor">.d</span>(<span class="hljs-string">"AppOps"</span>, <span class="hljs-string">"AppOpsService published"</span>)<span class="hljs-comment">;</span> LocalServices<span class="hljs-preprocessor">.addService</span>(ActivityManagerInternal<span class="hljs-preprocessor">.class</span>, new LocalService())<span class="hljs-comment">;</span> }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
这里有的人可能觉得奇怪,怎么这个start是一个private方法?上面使用mService.start();能访问吗?是的,可以访问的,虽然它是一个私有方法!这里可以参考本人的另一篇文章:
http://blog.youkuaiyun.com/baniel01/article/details/51776120
这里的start方法很是简单,首先是调用Process类的removeAllProcessGroups方法移除所有的进程组,清空所有记录;然后就是启动ProcessCpuThread线程,mProcessCpuThread这个对象就是在刚才的构造器中初始化的;下面是发布BatteryStatsService,调用的是publish方法:
publish@BatteryStatsService.java
<code class="hljs avrasm has-numbering">public void publish(Context context) { mContext = context<span class="hljs-comment">;</span> ServiceManager<span class="hljs-preprocessor">.addService</span>(BatteryStats<span class="hljs-preprocessor">.SERVICE</span>_NAME, asBinder())<span class="hljs-comment">;</span> mStats<span class="hljs-preprocessor">.setNumSpeedSteps</span>(new PowerProfile(mContext)<span class="hljs-preprocessor">.getNumSpeedSteps</span>())<span class="hljs-comment">;</span> mStats<span class="hljs-preprocessor">.setRadioScanningTimeout</span>(mContext<span class="hljs-preprocessor">.getResources</span>()<span class="hljs-preprocessor">.getInteger</span>( <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.integer</span><span class="hljs-preprocessor">.config</span>_radioScanningTimeout) * <span class="hljs-number">1000</span>L)<span class="hljs-comment">;</span> mStats<span class="hljs-preprocessor">.setPowerProfile</span>(new PowerProfile(context))<span class="hljs-comment">;</span> }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li></ul>
我们看到,这里首先就是将Battery stats服务注册到SM中去,然后就是设置一些运行时参数,具体这些参数是什么含义,读者可以自己分析一下BatteryStatsService的实现,这里我们就不详细分析了。
start方法的接下来的操作就是发布AppOpsService了,AppOpsService这个服务是提供android app ops服务的,什么是android app ops服务呢?App Ops是在android 4.3中加入的一个权限管理框架,这个框架可以让你自由地赋予或者撤销某个app的权限,方便管理,下图是操作时候的界面:
关于android app ops,详见:
http://www.androidauthority.com/app-ops-need-know-324850/
下面是AppOpsService的publish方法:
publish@AppOpsService.java
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">publish</span>(Context context) { mContext = context; ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder()); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
我们看到,这里就更加简单了,直接就是向SM注册服务。
好了,如果读者还没有晕掉的话,你会知道上面我们都是在分析SystemServiceManager中的startService方法。。。。。(android的代码真是繁杂,长篇大论,真是烦人!)到目前为止,我们的分析流程是这样的:
1. tartBootstrapServices@SystemServer.java
2. startService@SystemServiceManager.java
3. Lifecycle@ActivityManagerService.java
4. onStart@Lifecycle
5. start@ActivityManagerService.java
现在我们回过头来看下startBootstrapServices@SystemServer.java中AMS的启动部分:
<code class="hljs avrasm has-numbering">// Activity manager runs the show. mActivityManagerService = mSystemServiceManager<span class="hljs-preprocessor">.startService</span>( ActivityManagerService<span class="hljs-preprocessor">.Lifecycle</span><span class="hljs-preprocessor">.class</span>)<span class="hljs-preprocessor">.getService</span>()<span class="hljs-comment">;</span> mActivityManagerService<span class="hljs-preprocessor">.setSystemServiceManager</span>(mSystemServiceManager)<span class="hljs-comment">;</span> mActivityManagerService<span class="hljs-preprocessor">.setInstaller</span>(installer)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>
我们发现我们刚刚分析完了mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class)这部分的逻辑!!在这方法调用完成之后会返回Lifecycle类的对象(上面讲解过,不知道你是不是记得??),然后调用这个对象的getService方法赋值给mActivityManagerService,getService方法定义如下:
getService@Lifecycle
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> ActivityManagerService <span class="hljs-title">getService</span>() { <span class="hljs-keyword">return</span> mService; }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
而这里的mService就是在Lifecycle构造器中实例化的ActivityManagerService对象。
接下来在SystemServer.java中的操作就是调用AMS的setSystemServiceManager来将SystemServiceManager类的对象设置进去:
setSystemServiceManager@ActivityManagerService
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSystemServiceManager</span>(SystemServiceManager mgr) { mSystemServiceManager = mgr; }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
这里就只是将对象保存下来,以后会使用到。SystemServiceManager是一个创建,启动,和管理其他有关SystemService类系统服务的管理类,我们从这个类的代码注释也能看到:
/**
* Manages creating, starting, and other lifecycle events of
* {@link com.android.server.SystemService system services}.
*
* {@hide}
*/
这里说的很清楚,并且这个类的方法也是简单明了,具体这个类在AMS中怎么使用,我们后面分析AMS的业务逻辑的时候会提到。在startBootstrapServices@SystemServer.java的最后就是调用setInstaller方法将installer设置进去。installer是用来安装app的,我们的AMS使用它只是想在AMS的启动完成的时候调用installer的markBootComplete方法告诉它现在AMS启动完成了,installer可以进行工作了。这个调用是在AMS的finishBooting方法中调用的,finishBooting是ActivityStackSupervisor中初始化完毕之后回调的,ActivityStackSupervisor是用来管理ActivityStack的,这个类是android 5.0中新引入的。这部分涉及到ActivityStack的管理,所以这里不过多涉及,后面我们分析ActivityStack实现时再来详述这部分。现在大家只要知道,AMS启动最后它的finishBooting会被ActivityStackSupervisor回调,然后这个方法中会调用installer的markBootComplete,并且还会调用SystemServiceManager的startBootPhase通知启动的阶段信息:
startBootPhase@SystemServiceManager.java
<code class="hljs java has-numbering"><span class="hljs-javadoc">/** * Starts the specified boot phase for all system services that have been started up to * this point. * *<span class="hljs-javadoctag"> @param</span> phase The boot phase to start. */</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">startBootPhase</span>(<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> phase) { <span class="hljs-keyword">if</span> (phase <= mCurrentPhase) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(<span class="hljs-string">"Next phase must be larger than previous"</span>); } mCurrentPhase = phase; Slog.i(TAG, <span class="hljs-string">"Starting phase "</span> + mCurrentPhase); <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> serviceLen = mServices.size(); <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < serviceLen; i++) { <span class="hljs-keyword">final</span> SystemService service = mServices.get(i); <span class="hljs-keyword">try</span> { service.onBootPhase(mCurrentPhase); } <span class="hljs-keyword">catch</span> (Exception ex) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failed to boot service "</span> + service.getClass().getName() + <span class="hljs-string">": onBootPhase threw an exception during phase "</span> + mCurrentPhase, ex); } } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>
这部分代码比较简单,可以看到SystemServiceManager会从mServices列表中检出所有的service并且调用他们的onBootPhase方法通知启动的阶段信息。
到这里,AMS启动只是完成基本的准备阶段,下面还有很多的工作需要做的,大家有点耐心啊~~AMS作为android系统的重量级的服务,怎么会就那么简单呢??你说是吧?还是踏踏实实地看代码吧~~~~
接下的操作还是在startBootstrapServices方法中:
startBootstrapServices@SystemServer.java
<code class="hljs cs has-numbering"><span class="hljs-comment">// Now that the power manager has been started, let the activity manager</span> <span class="hljs-comment">// initialize power management features.</span> mActivityManagerService.initPowerManagement();</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
这里的操作比较简单,注释中说道,既然power manager已经启动了,那么我们的AMS就可以初始化和battery stats相关的工作了。这里我们暂时先不详细分析initPowerManagement的过程,后面我们分析AMS的电源部分的时候会详细说明这一块的内容。接着往下看startBootstrapServices的中关于AMS的代码:
<code class="hljs sql has-numbering">// <span class="hljs-operator"><span class="hljs-keyword">Set</span> up the Application instance <span class="hljs-keyword">for</span> the system process <span class="hljs-keyword">and</span> <span class="hljs-keyword">get</span> started. mActivityManagerService.setSystemProcess();</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>
这是startBootstrapServices中关于AMS的最后一个操作了,现在大家想一想,我们的AMS是一个Binder公共服务,每一个app都能通过getSystemService找到它的,但是到目前为止我们并没有看到任何关于在Binder中注册服务的逻辑啊?现在我们看一下setSystemProcess的实现:
setSystemProcess@ActivityManagerService.java
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setSystemProcess</span>() { <span class="hljs-keyword">try</span> { ServiceManager.addService(Context.ACTIVITY_SERVICE, <span class="hljs-keyword">this</span>, <span class="hljs-keyword">true</span>); ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); ServiceManager.addService(<span class="hljs-string">"meminfo"</span>, <span class="hljs-keyword">new</span> MemBinder(<span class="hljs-keyword">this</span>)); ServiceManager.addService(<span class="hljs-string">"gfxinfo"</span>, <span class="hljs-keyword">new</span> GraphicsBinder(<span class="hljs-keyword">this</span>)); ServiceManager.addService(<span class="hljs-string">"dbinfo"</span>, <span class="hljs-keyword">new</span> DbBinder(<span class="hljs-keyword">this</span>)); <span class="hljs-keyword">if</span> (MONITOR_CPU_USAGE) { ServiceManager.addService(<span class="hljs-string">"cpuinfo"</span>, <span class="hljs-keyword">new</span> CpuBinder(<span class="hljs-keyword">this</span>)); } ServiceManager.addService(<span class="hljs-string">"permission"</span>, <span class="hljs-keyword">new</span> PermissionController(<span class="hljs-keyword">this</span>)); ServiceManager.addService(<span class="hljs-string">"processinfo"</span>, <span class="hljs-keyword">new</span> ProcessInfoService(<span class="hljs-keyword">this</span>)); ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( <span class="hljs-string">"android"</span>, STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) { ProcessRecord app = newProcessRecordLocked(info, info.processName, <span class="hljs-keyword">false</span>, <span class="hljs-number">0</span>); app.persistent = <span class="hljs-keyword">true</span>; app.pid = MY_PID; app.maxAdj = ProcessList.SYSTEM_ADJ; app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); <span class="hljs-keyword">synchronized</span> (mPidsSelfLocked) { mPidsSelfLocked.put(app.pid, app); } updateLruProcessLocked(app, <span class="hljs-keyword">false</span>, <span class="hljs-keyword">null</span>); updateOomAdjLocked(); } } <span class="hljs-keyword">catch</span> (PackageManager.NameNotFoundException e) { <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException( <span class="hljs-string">"Unable to find android system package"</span>, e); } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li></ul>
就是这里了,我们看到这个方法上来的第一句就是ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);这句话就是我们想要找的,这句话的意思就是通过Binder向系统服务大管家ServiceManager(SM)注册我们的服务,这样android中的其他进程就可以通过context的getSystemService找到我们的服务了。这个方法中的接下来的代码让我们感觉AMS挺不务正业的,它还分管着meminfo,gfxinfo,dbinfo,cpuinfo,permission,processinfo等业务,还真是忙啊!这里我们先不看这些业务,因为我们知道只有Activity的管理业务才是AMS的主页,其他的都只是副业而已了。
SystemServer在启动完成所有的服务之后,将调用AMS的systemReady()方法,这个方法是android系统进入用户交互阶段前最后进行的准备工作,这个方法比较长,我们分段分析一下它:
1). 如果现在已经启动完毕再次调用的话,就执行回调代码
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">systemReady</span>(<span class="hljs-keyword">final</span> Runnable goingCallback) { <span class="hljs-keyword">synchronized</span>(<span class="hljs-keyword">this</span>) { <span class="hljs-keyword">if</span> (mSystemReady) { <span class="hljs-comment">// If we're done calling all the receivers, run the next "boot phase" passed in</span> <span class="hljs-comment">// by the SystemServer</span> <span class="hljs-keyword">if</span> (goingCallback != <span class="hljs-keyword">null</span>) { goingCallback.run(); } <span class="hljs-keyword">return</span>; }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>
首先我们看到,这个方法中的全部代码都是处在保护区中的,也就是说必须保证线程间安全,刚开始我们的mSystemReady是false,所以这里的代码不会执行
<code class="hljs avrasm has-numbering">mLocalDeviceIdleController = LocalServices<span class="hljs-preprocessor">.getService</span>(DeviceIdleController<span class="hljs-preprocessor">.LocalService</span><span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>
这里是获得设备idle控制器,主要用于广播发送中的控制,后面我们分析广播机制的时候会提到这个内容。
2). 装载系统用户的profile id
<code class="hljs scss has-numbering"><span class="hljs-comment">// Make sure we have the current profile info, since it is needed for</span> <span class="hljs-comment">// security checks.</span> <span class="hljs-function">updateCurrentProfileIdsLocked()</span>;</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
这部分代码是十分重要的,这里就是装载系统的用户ID的profile,用于后面的权限检查,这个是比较重要的信息,尤其是在android多用户的情况下,根据用户的ID配置赋予不同的权限。
3).重建recent task
<code class="hljs avrasm has-numbering">mRecentTasks<span class="hljs-preprocessor">.clear</span>()<span class="hljs-comment">;</span> mRecentTasks<span class="hljs-preprocessor">.addAll</span>(mTaskPersister<span class="hljs-preprocessor">.restoreTasksLocked</span>())<span class="hljs-comment">;</span> mRecentTasks<span class="hljs-preprocessor">.cleanupLocked</span>(UserHandle<span class="hljs-preprocessor">.USER</span>_ALL)<span class="hljs-comment">;</span> mTaskPersister<span class="hljs-preprocessor">.startPersisting</span>()<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
这里是在android 5.0之后才有的部分,这部分的主要工作就是重建带有persistent标记的task。在android 5.0中支持带有persistent标记的task,这些task在系统关机的时候,系统会把它的信息保存在系统的/data/system/recent_tasks目录下的xml文件中,系统重启的时候通过这些文件会重新创建task。下面是我的机器中的/data/system/recent_tasks目录内容:
我们随便打开一个文件看下内容:
<code class="hljs xml has-numbering"><span class="hljs-pi"><?xml version='1.0' encoding='utf-8' standalone='yes' ?></span> <span class="hljs-tag"><<span class="hljs-title">task</span> <span class="hljs-attribute">task_id</span>=<span class="hljs-value">"13"</span> <span class="hljs-attribute">real_activity</span>=<span class="hljs-value">"com.android.quicksearchbox/.SearchActivity"</span> <span class="hljs-attribute">affinity</span>=<span class="hljs-value">"com.android.quicksearchbox"</span> <span class="hljs-attribute">root_has_reset</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">auto_remove_recents</span>=<span class="hljs-value">"false"</span> <span class="hljs-attribute">asked_compat_mode</span>=<span class="hljs-value">"false"</span> <span class="hljs-attribute">user_id</span>=<span class="hljs-value">"0"</span> <span class="hljs-attribute">effective_uid</span>=<span class="hljs-value">"10049"</span> <span class="hljs-attribute">task_type</span>=<span class="hljs-value">"0"</span> <span class="hljs-attribute">first_active_time</span>=<span class="hljs-value">"12804324289"</span> <span class="hljs-attribute">last_active_time</span>=<span class="hljs-value">"12804367378"</span> <span class="hljs-attribute">last_time_moved</span>=<span class="hljs-value">"12804324278"</span> <span class="hljs-attribute">never_relinquish_identity</span>=<span class="hljs-value">"true"</span> <span class="hljs-attribute">task_description_color</span>=<span class="hljs-value">"ffe6e6e6"</span> <span class="hljs-attribute">task_affiliation_color</span>=<span class="hljs-value">"-1644826"</span> <span class="hljs-attribute">task_affiliation</span>=<span class="hljs-value">"13"</span> <span class="hljs-attribute">prev_affiliation</span>=<span class="hljs-value">"-1"</span> <span class="hljs-attribute">next_affiliation</span>=<span class="hljs-value">"-1"</span> <span class="hljs-attribute">calling_uid</span>=<span class="hljs-value">"10049"</span> <span class="hljs-attribute">calling_package</span>=<span class="hljs-value">"com.android.quicksearchbox"</span> <span class="hljs-attribute">resizeable</span>=<span class="hljs-value">"false"</span> <span class="hljs-attribute">privileged</span>=<span class="hljs-value">"false"</span>></span> <span class="hljs-tag"><<span class="hljs-title">intent</span> <span class="hljs-attribute">action</span>=<span class="hljs-value">"android.search.action.GLOBAL_SEARCH"</span> <span class="hljs-attribute">component</span>=<span class="hljs-value">"com.android.quicksearchbox/.SearchActivity"</span> <span class="hljs-attribute">flags</span>=<span class="hljs-value">"14200000"</span> /></span> <span class="hljs-tag"></<span class="hljs-title">task</span>></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul>
这里记录的是android的google搜索框task的信息。
4). 广播升级更新的intent
<code class="hljs java has-numbering"><span class="hljs-comment">// Check to see if there are any update receivers to run.</span> <span class="hljs-keyword">if</span> (!mDidUpdate) { <span class="hljs-keyword">if</span> (mWaitingUpdate) { <span class="hljs-keyword">return</span>; } <span class="hljs-keyword">final</span> ArrayList<ComponentName> doneReceivers = <span class="hljs-keyword">new</span> ArrayList<ComponentName>(); mWaitingUpdate = deliverPreBootCompleted(<span class="hljs-keyword">new</span> Runnable() { <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span>() { <span class="hljs-keyword">synchronized</span> (ActivityManagerService.<span class="hljs-keyword">this</span>) { mDidUpdate = <span class="hljs-keyword">true</span>; } showBootMessage(mContext.getText( R.string.android_upgrading_complete), <span class="hljs-keyword">false</span>); writeLastDonePreBootReceivers(doneReceivers); systemReady(goingCallback); } }, doneReceivers, UserHandle.USER_OWNER); <span class="hljs-keyword">if</span> (mWaitingUpdate) { <span class="hljs-keyword">return</span>; } mDidUpdate = <span class="hljs-keyword">true</span>; } mAppOpsService.systemReady(); mSystemReady = <span class="hljs-keyword">true</span>;</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li></ul>
这里的代码就是用来处理android系统升级过程的,android系统升级的时候,系统的模块或者app也是需要开机的时候完成一些更新,例如重新整理数据等操作。这里我们调用了deliverPreBootCompleted方法发送了一个ACTION_PRE_BOOT_COMPLETED的消息通知这些模块。需要注意的是,这个消息只会发送给系统级别的app,并不会发送给第三方的app,具体的接受模块定义在/data/system/called_pre_boots.dat文件中,下面是我手机上的文件内容:
<code class="hljs vbnet has-numbering"><span class="hljs-comment">'6.0.1RELeng.baniel.20160128.114223com.android.providers.calendar6com.android.providers.calendar.CalendarUpgradeReceivercom.android.providers.contacts6com.android.providers.contacts.ContactsUpgradeReceivercom.android.managedprovisioning/com.android.managedprovisioning.PreBootListenercom.android.providers.media0com.android.providers.media.MediaUpgradeReceivercom.android.settings(com.android.settings.ManagedProfileSetup</span></code><ul style="" class="pre-numbering"><li>1</li></ul>
可以看到这里都是一些系统级别的模块。
5). 清理多余进程,除了persistent进程
<code class="hljs java has-numbering"> ArrayList<ProcessRecord> procsToKill = <span class="hljs-keyword">null</span>; <span class="hljs-keyword">synchronized</span>(mPidsSelfLocked) { <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i=mPidsSelfLocked.size()-<span class="hljs-number">1</span>; i>=<span class="hljs-number">0</span>; i--) { ProcessRecord proc = mPidsSelfLocked.valueAt(i); <span class="hljs-keyword">if</span> (!isAllowedWhileBooting(proc.info)){ <span class="hljs-keyword">if</span> (procsToKill == <span class="hljs-keyword">null</span>) { procsToKill = <span class="hljs-keyword">new</span> ArrayList<ProcessRecord>(); } procsToKill.add(proc); } } } <span class="hljs-keyword">synchronized</span>(<span class="hljs-keyword">this</span>) { <span class="hljs-keyword">if</span> (procsToKill != <span class="hljs-keyword">null</span>) { <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i=procsToKill.size()-<span class="hljs-number">1</span>; i>=<span class="hljs-number">0</span>; i--) { ProcessRecord proc = procsToKill.get(i); Slog.i(TAG, <span class="hljs-string">"Removing system update proc: "</span> + proc); removeProcessLocked(proc, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>, <span class="hljs-string">"system update done"</span>); } } <span class="hljs-comment">// Now that we have cleaned up any update processes, we</span> <span class="hljs-comment">// are ready to start launching real processes and know that</span> <span class="hljs-comment">// we won't trample on them any more.</span> mProcessesReady = <span class="hljs-keyword">true</span>; }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li></ul>
这段代码的作用就是找到已经启动的应用进程,然后杀死他们,为什么呢?目的就是为了在home启动之前准备一个干净的环境。home启动之前的环境怎么会不干净呢?我们之前提到了,android系统会发送一个intent消息给系统模块,通知他们进行相应的升级,这里的这些模块就是有可能会在home运行之前运行的,为了不让这些模块的运行干扰我们home的正常逻辑,所以要就杀死他们。但是这里我们看到代码中定义了有一种进程是不会被杀死的,就是isAllowedWhileBooting返回true的进程,这个方法会检查进程是否带有FLAG_PERSISTENT标记,如果有的话就不用杀死他们,因为带有这个标识的进程下面我们还有启动他们的。
<code class="hljs avrasm has-numbering">Slog<span class="hljs-preprocessor">.i</span>(TAG, <span class="hljs-string">"System now ready"</span>)<span class="hljs-comment">;</span> EventLog<span class="hljs-preprocessor">.writeEvent</span>(EventLogTags<span class="hljs-preprocessor">.BOOT</span>_PROGRESS_AMS_READY, SystemClock<span class="hljs-preprocessor">.uptimeMillis</span>())<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
这里就是打印event的log,没有什么逻辑。
6). 如果是工厂测试模式,则启动工厂测试模块
<code class="hljs avrasm has-numbering"> synchronized(this) { // Make sure we have no pre-ready processes sitting around. if (mFactoryTest == FactoryTest<span class="hljs-preprocessor">.FACTORY</span>_TEST_LOW_LEVEL) { ResolveInfo ri = mContext<span class="hljs-preprocessor">.getPackageManager</span>() <span class="hljs-preprocessor">.resolveActivity</span>(new Intent(Intent<span class="hljs-preprocessor">.ACTION</span>_FACTORY_TEST), STOCK_PM_FLAGS)<span class="hljs-comment">;</span> CharSequence errorMsg = null<span class="hljs-comment">;</span> if (ri != null) { ActivityInfo ai = ri<span class="hljs-preprocessor">.activityInfo</span><span class="hljs-comment">;</span> ApplicationInfo app = ai<span class="hljs-preprocessor">.applicationInfo</span><span class="hljs-comment">;</span> if ((app<span class="hljs-preprocessor">.flags</span>&ApplicationInfo<span class="hljs-preprocessor">.FLAG</span>_SYSTEM) != <span class="hljs-number">0</span>) { mTopAction = Intent<span class="hljs-preprocessor">.ACTION</span>_FACTORY_TEST<span class="hljs-comment">;</span> mTopData = null<span class="hljs-comment">;</span> mTopComponent = new ComponentName(app<span class="hljs-preprocessor">.packageName</span>, ai<span class="hljs-preprocessor">.name</span>)<span class="hljs-comment">;</span> } else { errorMsg = mContext<span class="hljs-preprocessor">.getResources</span>()<span class="hljs-preprocessor">.getText</span>( <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.string</span><span class="hljs-preprocessor">.factorytest</span>_not_system)<span class="hljs-comment">;</span> } } else { errorMsg = mContext<span class="hljs-preprocessor">.getResources</span>()<span class="hljs-preprocessor">.getText</span>( <span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.string</span><span class="hljs-preprocessor">.factorytest</span>_no_action)<span class="hljs-comment">;</span> } if (errorMsg != null) { mTopAction = null<span class="hljs-comment">;</span> mTopData = null<span class="hljs-comment">;</span> mTopComponent = null<span class="hljs-comment">;</span> Message msg = Message<span class="hljs-preprocessor">.obtain</span>()<span class="hljs-comment">;</span> msg<span class="hljs-preprocessor">.what</span> = SHOW_FACTORY_ERROR_MSG<span class="hljs-comment">;</span> msg<span class="hljs-preprocessor">.getData</span>()<span class="hljs-preprocessor">.putCharSequence</span>(<span class="hljs-string">"msg"</span>, errorMsg)<span class="hljs-comment">;</span> mUiHandler<span class="hljs-preprocessor">.sendMessage</span>(msg)<span class="hljs-comment">;</span> } } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li></ul>
这是判断如果当前系统处于“工厂测试模式”的话,就会启动用于工厂测试的模块。我们的手机在生产出厂的时候,都要进行工厂测试的,在工厂模式下运行的程序需要响应intent ACTION_FACTORY_TEST消息。这里主要就是查找响应该消息的程序,并且放在mTopComponent中,如果没有找到,就发送工场测试失败的消息。
7). 读取设置信息
<code class="hljs scss has-numbering"> <span class="hljs-function">retrieveSettings()</span>; <span class="hljs-function">loadResourcesOnSystemReady()</span>;</code><ul style="" class="pre-numbering"><li>1</li><li>2</li></ul>
这里调用retrieveSettings来读取设置,这个方法中的读取代码如下所示:
<code class="hljs avrasm has-numbering"> private void retrieveSettings() { final ContentResolver resolver = mContext<span class="hljs-preprocessor">.getContentResolver</span>()<span class="hljs-comment">;</span> String debugApp = Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.getString</span>( resolver, Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.DEBUG</span>_APP)<span class="hljs-comment">;</span> boolean waitForDebugger = Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.getInt</span>( resolver, Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.WAIT</span>_FOR_DEBUGGER, <span class="hljs-number">0</span>) != <span class="hljs-number">0</span><span class="hljs-comment">;</span> boolean alwaysFinishActivities = Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.getInt</span>( resolver, Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.ALWAYS</span>_FINISH_ACTIVITIES, <span class="hljs-number">0</span>) != <span class="hljs-number">0</span><span class="hljs-comment">;</span> boolean forceRtl = Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.getInt</span>( resolver, Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.DEVELOPMENT</span>_FORCE_RTL, <span class="hljs-number">0</span>) != <span class="hljs-number">0</span><span class="hljs-comment">;</span> // Transfer any global setting for forcing RTL layout, into a System Property SystemProperties<span class="hljs-preprocessor">.set</span>(Settings<span class="hljs-preprocessor">.Global</span><span class="hljs-preprocessor">.DEVELOPMENT</span>_FORCE_RTL, forceRtl ? <span class="hljs-string">"1"</span>:<span class="hljs-string">"0"</span>)<span class="hljs-comment">;</span> Configuration configuration = new Configuration()<span class="hljs-comment">;</span> Settings<span class="hljs-preprocessor">.System</span><span class="hljs-preprocessor">.getConfiguration</span>(resolver, configuration)<span class="hljs-comment">;</span> if (forceRtl) { // This will take care of setting the correct layout direction flags configuration<span class="hljs-preprocessor">.setLayoutDirection</span>(configuration<span class="hljs-preprocessor">.locale</span>)<span class="hljs-comment">;</span> } synchronized (this) { mDebugApp = mOrigDebugApp = debugApp<span class="hljs-comment">;</span> mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger<span class="hljs-comment">;</span> mAlwaysFinishActivities = alwaysFinishActivities<span class="hljs-comment">;</span> // This happens before any activities are started, so we can // change mConfiguration <span class="hljs-keyword">in</span>-place. updateConfigurationLocked(configuration, null, false, true)<span class="hljs-comment">;</span> if (DEBUG_CONFIGURATION) Slog<span class="hljs-preprocessor">.v</span>(TAG_CONFIGURATION, <span class="hljs-string">"Initial config: "</span> + mConfiguration)<span class="hljs-comment">;</span> } }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li></ul>
我们看到,这里就读取一下4个设置:
DEBUG_APP:需要调试的app名称
WAIT_FOR_DEBUGGER:如果值为1,表示启动调试的app时需要先等待调试器,否则正常启动
ALWAYS_FINISH_ACTIVITIES:值为1的时候,表示activity已经不再需要,系统需要立即清理他们,这个可以在setting的开发者选项中设置。
DEVELOPMENT_FORCE_RTL:值为1表示要将系统设置为从右到左的模式(西亚地区部分语言,如希伯来语)。
接着systemReady的分析,在上面的方法之后调用了loadResourcesOnSystemReady方法从资源文件中读取了几个缺省的系统配置信息:
<code class="hljs avrasm has-numbering"> <span class="hljs-comment">/** Loads resources after the current configuration has been set. */</span> private void loadResourcesOnSystemReady() { final Resources res = mContext<span class="hljs-preprocessor">.getResources</span>()<span class="hljs-comment">;</span> mHasRecents = res<span class="hljs-preprocessor">.getBoolean</span>(<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.bool</span><span class="hljs-preprocessor">.config</span>_hasRecents)<span class="hljs-comment">;</span> mThumbnailWidth = res<span class="hljs-preprocessor">.getDimensionPixelSize</span>(<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.dimen</span><span class="hljs-preprocessor">.thumbnail</span>_width)<span class="hljs-comment">;</span> mThumbnailHeight = res<span class="hljs-preprocessor">.getDimensionPixelSize</span>(<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.android</span><span class="hljs-preprocessor">.internal</span><span class="hljs-preprocessor">.R</span><span class="hljs-preprocessor">.dimen</span><span class="hljs-preprocessor">.thumbnail</span>_height)<span class="hljs-comment">;</span> }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>
继续看systemReady接下来的代码:
8).打开URI读取权限
<code class="hljs java has-numbering"> <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) { readGrantedUriPermissionsLocked(); } </code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>
上面我们打开了URI权限的配置文件,这里我们就读取URI权限。
9).执行参数的callback,完成SystemServer的处理逻辑
<code class="hljs cs has-numbering"><span class="hljs-keyword">if</span> (goingCallback != <span class="hljs-keyword">null</span>) goingCallback.run();</code><ul style="" class="pre-numbering"><li>1</li></ul>
systemReady方法的参数就是一个Runnable对象,这里当这个对象不为空的时候,回调它的run方法,这个run方法主要执行SystemServer自己在这块的逻辑,主要就是一些后续的设置,准备,启动system ui,AMS开始观察本地程序的crash,和回调很多模块的systemReady和systemrunning方法。这个回调方法比较长,这里就不详细分析了。
<code class="language-mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START, hljs avrasm has-numbering">Integer<span class="hljs-preprocessor">.toString</span>(mCurrentUserId), mCurrentUserId)<span class="hljs-comment">;</span> mBatteryStatsService<span class="hljs-preprocessor">.noteEvent</span>(BatteryStats<span class="hljs-preprocessor">.HistoryItem</span><span class="hljs-preprocessor">.EVENT</span>_USER_FOREGROUND_START, Integer<span class="hljs-preprocessor">.toString</span>(mCurrentUserId), mCurrentUserId)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
这里通知BatteryStatsService当前用户启动消息(下面即将启动),BatteryStatsService会开始电池数据的统计分析。
10). 启动当前用户
<code class="hljs avrasm has-numbering"> mSystemServiceManager<span class="hljs-preprocessor">.startUser</span>(mCurrentUserId)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li></ul>
这里开始启动当前用户,为用户和系统交互做home桌面启动前的准备。
11).启动带有FLAG_PERSISTENT标记的应用,并且启动home launcher
<code class="hljs java has-numbering"> <span class="hljs-keyword">synchronized</span> (<span class="hljs-keyword">this</span>) { <span class="hljs-comment">// 如果不是工厂测试模式</span> <span class="hljs-keyword">if</span> (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { <span class="hljs-keyword">try</span> { <span class="hljs-comment">// 查找带有persistent标记的app</span> List apps = AppGlobals.getPackageManager(). getPersistentApplications(STOCK_PM_FLAGS); <span class="hljs-keyword">if</span> (apps != <span class="hljs-keyword">null</span>) { <span class="hljs-keyword">int</span> N = apps.size(); <span class="hljs-keyword">int</span> i; <span class="hljs-keyword">for</span> (i=<span class="hljs-number">0</span>; i<N; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); <span class="hljs-comment">// 排除掉包名为“android”的app,因为前面已经加入过了。</span> <span class="hljs-keyword">if</span> (info != <span class="hljs-keyword">null</span> && !info.packageName.equals(<span class="hljs-string">"android"</span>)) { addAppLocked(info, <span class="hljs-keyword">false</span>, <span class="hljs-keyword">null</span> <span class="hljs-comment">/* ABI override */</span>); } } } } <span class="hljs-keyword">catch</span> (RemoteException ex) { <span class="hljs-comment">// pm is in same process, this will never happen.</span> } } <span class="hljs-comment">// Start up initial activity.</span> mBooting = <span class="hljs-keyword">true</span>; <span class="hljs-comment">// 启动home桌面app</span> startHomeActivityLocked(mCurrentUserId, <span class="hljs-string">"systemReady"</span>); <span class="hljs-keyword">try</span> { <span class="hljs-keyword">if</span> (AppGlobals.getPackageManager().hasSystemUidErrors()) { Slog.e(TAG, <span class="hljs-string">"UIDs on the system are inconsistent, you need to wipe your"</span> + <span class="hljs-string">" data partition or your device will be unstable."</span>); mUiHandler.obtainMessage(SHOW_UID_ERROR_MSG).sendToTarget(); } } <span class="hljs-keyword">catch</span> (RemoteException e) { } <span class="hljs-keyword">if</span> (!Build.isBuildConsistent()) { Slog.e(TAG, <span class="hljs-string">"Build fingerprint is not consistent, warning user"</span>); mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget(); } <span class="hljs-keyword">long</span> ident = Binder.clearCallingIdentity(); <span class="hljs-keyword">try</span> { <span class="hljs-comment">// 发送用户启动完成的消息</span> Intent intent = <span class="hljs-keyword">new</span> Intent(Intent.ACTION_USER_STARTED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); broadcastIntentLocked(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, intent, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, <span class="hljs-number">0</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, AppOpsManager.OP_NONE, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">false</span>, <span class="hljs-keyword">false</span>, MY_PID, Process.SYSTEM_UID, mCurrentUserId); intent = <span class="hljs-keyword">new</span> Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); broadcastIntentLocked(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, intent, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">new</span> IIntentReceiver.Stub() { <span class="hljs-annotation">@Override</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">performReceive</span>(Intent intent, <span class="hljs-keyword">int</span> resultCode, String data, Bundle extras, <span class="hljs-keyword">boolean</span> ordered, <span class="hljs-keyword">boolean</span> sticky, <span class="hljs-keyword">int</span> sendingUser) <span class="hljs-keyword">throws</span> RemoteException { } }, <span class="hljs-number">0</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">new</span> String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, <span class="hljs-keyword">null</span>, <span class="hljs-keyword">true</span>, <span class="hljs-keyword">false</span>, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } <span class="hljs-keyword">catch</span> (Throwable t) { Slog.wtf(TAG, <span class="hljs-string">"Failed sending first user broadcasts"</span>, t); } <span class="hljs-keyword">finally</span> { Binder.restoreCallingIdentity(ident); } <span class="hljs-comment">// 开始恢复显示activity栈顶的界面,也就是home的主界面。</span> mStackSupervisor.resumeTopActivitiesLocked(); sendUserSwitchBroadcastsLocked(-<span class="hljs-number">1</span>, mCurrentUserId); }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li><li>61</li><li>62</li><li>63</li><li>64</li><li>65</li><li>66</li><li>67</li><li>68</li><li>69</li><li>70</li><li>71</li><li>72</li><li>73</li><li>74</li><li>75</li><li>76</li></ul>
这段代码的作用就是启动带有FLAG_PERSISTENT标记的app,启动应用通过调用addAppLocked方法完成,这个方法后面我们分析AMS的进程管理的时候再详细描述。接着就是启动我们熟悉的home了,通过调用startHomeActivityLocked方法完成,这个方法会首先查找当前home启动器,然后再启动对应的启动器(因为用户可能会下载安装了第三方的启动器)。home启动完成之后,系统会发送ACTION_BOOT_COMPLETE消息,通知app系统启动完成。
到这里,AMS的主体业务才算是启动完毕。这里我们简单分析了一下android中的AMS的在开机过程中的启动流程,目的就是给大家关于AMS启动的一个清晰的结构,并不是要面面俱到。个人感觉,android中的任何一个模块拿出来的话代码量都是巨大的,怎么从这些代码中找到android的设计的整体架构呢?最好的办法还是,先整体再模块,先抽象再具体。也就是先要知道整体的情况是什么样的,然后再研究细节部分,不然的话很有可能会深陷android代码泥沼,不能自拔……