-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
275 lines (157 loc) · 286 KB
/
atom.xml
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>子墨不语</title>
<subtitle>路漫漫其修远兮,吾将上下而求索</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="http://www.molingyu.com/"/>
<updated>2017-11-09T18:07:00.830Z</updated>
<id>http://www.molingyu.com/</id>
<author>
<name>子墨</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>由DBUtils使用ResultHandler引出的一个关于JavaBean反射的问题</title>
<link href="http://www.molingyu.com/2017/11/10/%E7%94%B1DBUtils%E4%BD%BF%E7%94%A8ResultHandler%E5%BC%95%E5%87%BA%E7%9A%84%E4%B8%80%E4%B8%AA%E5%85%B3%E4%BA%8EJavaBean%E5%8F%8D%E5%B0%84%E7%9A%84%E9%97%AE%E9%A2%98/"/>
<id>http://www.molingyu.com/2017/11/10/由DBUtils使用ResultHandler引出的一个关于JavaBean反射的问题/</id>
<published>2017-11-09T18:07:00.830Z</published>
<updated>2017-11-09T18:07:00.830Z</updated>
<content type="html"><![CDATA[<p>今天搭建服务器,使用DBUtils处理数据库的时候,出了个小问题:<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> Device <span class="title">findById</span><span class="params">(String sn)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> String sql = <span class="string">"SELECT * FROM device WHERE sn=?"</span>;</div><div class="line"> QueryRunner runner = DBUtils.getQuerryRunner();</div><div class="line"> <span class="keyword">return</span> runner.query(sql, <span class="keyword">new</span> BeanHandler<>(Device.class), sn);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//定义业务Model定义</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Device</span> </span>{</div><div class="line"> <span class="keyword">public</span> String sn;</div><div class="line"> <span class="keyword">public</span> String uuid;</div><div class="line"> <span class="keyword">public</span> String name;</div><div class="line"> <span class="keyword">public</span> String chargeAddr;</div><div class="line"> <span class="keyword">public</span> String addr1;</div><div class="line"> <span class="keyword">public</span> String addr2;</div><div class="line"> <span class="keyword">public</span> String firmware;</div><div class="line"> <span class="keyword">public</span> Float compensation;</div><div class="line"> <span class="keyword">public</span> Long lastUpdateTime;</div><div class="line">}</div></pre></td></tr></table></figure></p><p>最终,<strong>runner.query(</strong>返回的结果,是一个空的Device对象,即其内部成员都是null值。 而当我把Device定义成标准的JavaBean对象的时候,才能够正常的返回结果。</p><p>那么,这是为什么呢? 源码是最好的老师…</p><h2 id="查看DBUtils的源码"><a href="#查看DBUtils的源码" class="headerlink" title="查看DBUtils的源码"></a>查看DBUtils的源码</h2><p>QueryRunner的源码位于:/commons-dbutils-1.7-sources.jar!/org/apache/commons/dbutils/QueryRunner.java</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <T> <span class="function">T <span class="title">query</span><span class="params">(String sql, ResultSetHandler<T> rsh, Object... params)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> Connection conn = <span class="keyword">this</span>.prepareConnection();</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.<T>query(conn, <span class="keyword">true</span>, sql, rsh, params);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">private</span> <T> <span class="function">T <span class="title">query</span><span class="params">(Connection conn, <span class="keyword">boolean</span> closeConn, String sql, ResultSetHandler<T> rsh, Object... params)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> </div><div class="line"> ......</div><div class="line"></div><div class="line"> PreparedStatement stmt = <span class="keyword">null</span>;</div><div class="line"> ResultSet rs = <span class="keyword">null</span>;</div><div class="line"> T result = <span class="keyword">null</span>;</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> stmt = <span class="keyword">this</span>.prepareStatement(conn, sql);</div><div class="line"> <span class="keyword">this</span>.fillStatement(stmt, params);</div><div class="line"> <span class="comment">//执行SQL语句,得到ResultSet结果集</span></div><div class="line"> rs = <span class="keyword">this</span>.wrap(stmt.executeQuery());</div><div class="line"> <span class="comment">//使用传入的rsh来处理结果集</span></div><div class="line"> result = rsh.handle(rs);</div><div class="line"></div><div class="line"> } <span class="keyword">catch</span> (SQLException e) {</div><div class="line"> <span class="keyword">this</span>.rethrow(e, sql, params);</div><div class="line"></div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> close(rs);</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> close(stmt);</div><div class="line"> <span class="keyword">if</span> (closeConn) {</div><div class="line"> close(conn);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> result;</div><div class="line"> }</div></pre></td></tr></table></figure><p>我们在调用的时候,传入了BeanHandler,所以使用了BeanHandler来处理结果集,其源码位于:/commons-dbutils-1.7-sources.jar!/org/apache/commons/dbutils/handlers/BeanHandler.java<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">static</span> <span class="keyword">final</span> RowProcessor ROW_PROCESSOR = <span class="keyword">new</span> BasicRowProcessor();</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">BeanHandler</span><span class="params">(Class<? extends T> type)</span> </span>{</div><div class="line"> <span class="keyword">this</span>(type, ArrayHandler.ROW_PROCESSOR);</div><div class="line">}</div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">BeanHandler</span><span class="params">(Class<? extends T> type, RowProcessor convert)</span> </span>{</div><div class="line"> <span class="keyword">this</span>.type = type;</div><div class="line"> <span class="keyword">this</span>.convert = convert;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> T <span class="title">handle</span><span class="params">(ResultSet rs)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> <span class="keyword">return</span> rs.next() ? <span class="keyword">this</span>.convert.toBean(rs, <span class="keyword">this</span>.type) : <span class="keyword">null</span>;</div><div class="line">}</div></pre></td></tr></table></figure></p><p>可见,在得到结果集之后,使用<strong>ArrayHandler.ROW_PROCESSOR.toBean()</strong>的方法来处理结果集</p><p>BasicRowProcessor源码:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"></div><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> BeanProcessor defaultConvert = <span class="keyword">new</span> BeanProcessor();</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">BasicRowProcessor</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">this</span>(defaultConvert);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">BasicRowProcessor</span><span class="params">(BeanProcessor convert)</span> </span>{</div><div class="line"> <span class="keyword">super</span>();</div><div class="line"> <span class="keyword">this</span>.convert = convert;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">public</span> <T> <span class="function">T <span class="title">toBean</span><span class="params">(ResultSet rs, Class<? extends T> type)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.convert.toBean(rs, type);</div><div class="line">}</div></pre></td></tr></table></figure></p><p>最终,调用到 /commons-dbutils-1.7-sources.jar!/org/apache/commons/dbutils/BeanProcessor.java 来处理<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <T> <span class="function">T <span class="title">toBean</span><span class="params">(ResultSet rs, Class<? extends T> type)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"><span class="comment">//首先初始化一个type实例,在本例中,为Device实例</span></div><div class="line"> T bean = <span class="keyword">this</span>.newInstance(type);</div><div class="line"> <span class="comment">//开始填实例内容</span></div><div class="line"> <span class="keyword">return</span> <span class="keyword">this</span>.populateBean(rs, bean);</div><div class="line">}</div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="keyword">public</span> <T> <span class="function">T <span class="title">populateBean</span><span class="params">(ResultSet rs, T bean)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"><span class="comment">//首先获得bean的成员属性列表</span></div><div class="line"> PropertyDescriptor[] props = <span class="keyword">this</span>.propertyDescriptors(bean.getClass());</div><div class="line"> /拿到结果集中包含的meta data数据,也就是我们的数据库列</div><div class="line"> ResultSetMetaData rsmd = rs.getMetaData();</div><div class="line"> <span class="keyword">int</span>[] columnToProperty = <span class="keyword">this</span>.mapColumnsToProperties(rsmd, props);</div><div class="line"></div><div class="line"> <span class="keyword">return</span> populateBean(rs, bean, props, columnToProperty);</div><div class="line">}</div><div class="line"></div><div class="line">......</div></pre></td></tr></table></figure></p><p>我们先来看bean属性成员列表的获取,入参为Class对象<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> PropertyDescriptor[] propertyDescriptors(Class<?> c)</div><div class="line"> <span class="keyword">throws</span> SQLException {</div><div class="line"> <span class="comment">// Introspector caches BeanInfo classes for better performance</span></div><div class="line"> BeanInfo beanInfo = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//通过Introspector.sgetBeanInfo获得对应Class的BeanInfo</span></div><div class="line"> beanInfo = Introspector.getBeanInfo(c);</div><div class="line"></div><div class="line"> } <span class="keyword">catch</span> (IntrospectionException e) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> SQLException(</div><div class="line"> <span class="string">"Bean introspection failed: "</span> + e.getMessage());</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> beanInfo.getPropertyDescriptors();</div><div class="line">}</div></pre></td></tr></table></figure></p><p>我们来看下src.zip!/java/beans/Introspector.java的getBeanInfo()方法<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> BeanInfo <span class="title">getBeanInfo</span><span class="params">(Class<?> beanClass)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> IntrospectionException</span></div><div class="line"><span class="function"></span>{</div><div class="line"><span class="comment">//显然isPackageAccessible()返回true,因此不走这里</span></div><div class="line"> <span class="keyword">if</span> (!ReflectUtil.isPackageAccessible(beanClass)) {</div><div class="line"> <span class="keyword">return</span> (<span class="keyword">new</span> Introspector(beanClass, <span class="keyword">null</span>, USE_ALL_BEANINFO)).getBeanInfo();</div><div class="line"> }</div><div class="line"> ThreadGroupContext context = ThreadGroupContext.getContext();</div><div class="line"> BeanInfo beanInfo;</div><div class="line"> <span class="keyword">synchronized</span> (declaredMethodCache) {</div><div class="line"> <span class="comment">//一开始没有掉用过putBeanInfo,因此这里获取得到的为null</span></div><div class="line"> beanInfo = context.getBeanInfo(beanClass);</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (beanInfo == <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">//最终走到这一步,构造beanClass的内省器,然后从该内省器中获取BeanInfo</span></div><div class="line"> beanInfo = <span class="keyword">new</span> Introspector(beanClass, <span class="keyword">null</span>, USE_ALL_BEANINFO).getBeanInfo();</div><div class="line"> <span class="keyword">synchronized</span> (declaredMethodCache) {</div><div class="line"> context.putBeanInfo(beanClass, beanInfo);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> beanInfo;</div><div class="line">}</div><div class="line"></div><div class="line">......</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">private</span> BeanInfo <span class="title">getBeanInfo</span><span class="params">()</span> <span class="keyword">throws</span> IntrospectionException </span>{</div><div class="line"></div><div class="line"> <span class="comment">// the evaluation order here is import, as we evaluate the</span></div><div class="line"> <span class="comment">// event sets and locate PropertyChangeListeners before we</span></div><div class="line"> <span class="comment">// look for properties.</span></div><div class="line"> BeanDescriptor bd = getTargetBeanDescriptor();</div><div class="line"> MethodDescriptor mds[] = getTargetMethodInfo();</div><div class="line"> EventSetDescriptor esds[] = getTargetEventInfo();</div><div class="line"> <span class="comment">//这便是我们要找的PropertyDescriptor[]数组了,这个数组是什么时候写进来的呢?</span></div><div class="line"> PropertyDescriptor pds[] = getTargetPropertyInfo();</div><div class="line"></div><div class="line"> <span class="keyword">int</span> defaultEvent = getTargetDefaultEventIndex();</div><div class="line"> <span class="keyword">int</span> defaultProperty = getTargetDefaultPropertyIndex();</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="keyword">new</span> GenericBeanInfo(bd, esds, defaultEvent, pds,</div><div class="line"> defaultProperty, mds, explicitBeanInfo);</div><div class="line"></div><div class="line">}</div></pre></td></tr></table></figure></p><p>我们来深入看getTargetPropertyInfo方法,这个方法比较长,需要细心的看</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div><div class="line">120</div><div class="line">121</div><div class="line">122</div><div class="line">123</div><div class="line">124</div><div class="line">125</div><div class="line">126</div><div class="line">127</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> PropertyDescriptor[] getTargetPropertyInfo() {</div><div class="line"></div><div class="line"> <span class="comment">// Check if the bean has its own BeanInfo that will provide</span></div><div class="line"> <span class="comment">// explicit information.</span></div><div class="line"> PropertyDescriptor[] explicitProperties = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">if</span> (explicitBeanInfo != <span class="keyword">null</span>) {</div><div class="line"> explicitProperties = getPropertyDescriptors(<span class="keyword">this</span>.explicitBeanInfo);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (explicitProperties == <span class="keyword">null</span> && superBeanInfo != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// We have no explicit BeanInfo properties. Check with our parent.</span></div><div class="line"> addPropertyDescriptors(getPropertyDescriptors(<span class="keyword">this</span>.superBeanInfo));</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < additionalBeanInfo.length; i++) {</div><div class="line"> addPropertyDescriptors(additionalBeanInfo[i].getPropertyDescriptors());</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (explicitProperties != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// Add the explicit BeanInfo data to our results.</span></div><div class="line"> addPropertyDescriptors(explicitProperties);</div><div class="line"></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//对于前面的Device.class,explicitBeanInfo、explicitProperties、additionalBeanInfo都为null,所以直接走到这里</span></div><div class="line"></div><div class="line"> <span class="comment">// Apply some reflection to the current class.</span></div><div class="line"></div><div class="line"> <span class="comment">// First get an array of all the public methods at this level</span></div><div class="line"> Method methodList[] = getPublicDeclaredMethods(beanClass);</div><div class="line"></div><div class="line"> <span class="comment">//这里是重点了:获得BeanClass的所有public方法,然后依次分析</span></div><div class="line"></div><div class="line"> <span class="comment">// Now analyze each method.</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < methodList.length; i++) {</div><div class="line"> Method method = methodList[i];</div><div class="line"> <span class="keyword">if</span> (method == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">// skip static methods.</span></div><div class="line"> <span class="keyword">int</span> mods = method.getModifiers();</div><div class="line"> <span class="keyword">if</span> (Modifier.isStatic(mods)) {</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"> String name = method.getName();</div><div class="line"> Class<?>[] argTypes = method.getParameterTypes();</div><div class="line"> Class<?> resultType = method.getReturnType();</div><div class="line"> <span class="keyword">int</span> argCount = argTypes.length;</div><div class="line"> <span class="comment">//这便是我们PropertyDescriptor[]的单个元素 pd</span></div><div class="line"> PropertyDescriptor pd = <span class="keyword">null</span>;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (name.length() <= <span class="number">3</span> && !name.startsWith(IS_PREFIX)) {</div><div class="line"> <span class="comment">// Optimization. Don't bother with invalid propertyNames.</span></div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (argCount == <span class="number">0</span>) {</div><div class="line"> <span class="comment">//如果无参方法,则看下是否以get开头</span></div><div class="line"> <span class="keyword">if</span> (name.startsWith(GET_PREFIX)) {</div><div class="line"> <span class="comment">// Simple getter</span></div><div class="line"> pd = <span class="keyword">new</span> PropertyDescriptor(<span class="keyword">this</span>.beanClass, name.substring(<span class="number">3</span>), method, <span class="keyword">null</span>);</div><div class="line"> <span class="comment">//看下方法返回类型是否为boolean、并且方法以is开头</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (resultType == <span class="keyword">boolean</span>.class && name.startsWith(IS_PREFIX)) {</div><div class="line"> <span class="comment">// Boolean getter</span></div><div class="line"> pd = <span class="keyword">new</span> PropertyDescriptor(<span class="keyword">this</span>.beanClass, name.substring(<span class="number">2</span>), method, <span class="keyword">null</span>);</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (argCount == <span class="number">1</span>) {</div><div class="line"> <span class="comment">//如果有个参数,则看下是否以get开头,并且参数类型为int类型</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">int</span>.class.equals(argTypes[<span class="number">0</span>]) && name.startsWith(GET_PREFIX)) {</div><div class="line"> pd = <span class="keyword">new</span> IndexedPropertyDescriptor(<span class="keyword">this</span>.beanClass, name.substring(<span class="number">3</span>), <span class="keyword">null</span>, <span class="keyword">null</span>, method, <span class="keyword">null</span>);</div><div class="line"> <span class="comment">//看下方法释放以set开头,并且返回类型为void空类型</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">void</span>.class.equals(resultType) && name.startsWith(SET_PREFIX)) {</div><div class="line"> <span class="comment">// Simple setter</span></div><div class="line"> pd = <span class="keyword">new</span> PropertyDescriptor(<span class="keyword">this</span>.beanClass, name.substring(<span class="number">3</span>), <span class="keyword">null</span>, method);</div><div class="line"> <span class="keyword">if</span> (throwsException(method, PropertyVetoException.class)) {</div><div class="line"> pd.setConstrained(<span class="keyword">true</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (argCount == <span class="number">2</span>) {</div><div class="line"> <span class="comment">//如果有两个参数,则检查1、返回类型释放为空, 第一个参数是否为int类型,然后方法开头是否以set开头</span></div><div class="line"> <span class="keyword">if</span> (<span class="keyword">void</span>.class.equals(resultType) && <span class="keyword">int</span>.class.equals(argTypes[<span class="number">0</span>]) && name.startsWith(SET_PREFIX)) {</div><div class="line"> pd = <span class="keyword">new</span> IndexedPropertyDescriptor(<span class="keyword">this</span>.beanClass, name.substring(<span class="number">3</span>), <span class="keyword">null</span>, <span class="keyword">null</span>, <span class="keyword">null</span>, method);</div><div class="line"> <span class="keyword">if</span> (throwsException(method, PropertyVetoException.class)) {</div><div class="line"> pd.setConstrained(<span class="keyword">true</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> } <span class="keyword">catch</span> (IntrospectionException ex) {</div><div class="line"> <span class="comment">// This happens if a PropertyDescriptor or IndexedPropertyDescriptor</span></div><div class="line"> <span class="comment">// constructor fins that the method violates details of the deisgn</span></div><div class="line"> <span class="comment">// pattern, e.g. by having an empty name, or a getter returning</span></div><div class="line"> <span class="comment">// void , or whatever.</span></div><div class="line"> pd = <span class="keyword">null</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//如果pd不为空,BeanClass的方法符合前面的条件,因此,将它通过addPropertyDescriptor方法添加到PropertyDescriptor列表中</span></div><div class="line"> <span class="keyword">if</span> (pd != <span class="keyword">null</span>) {</div><div class="line"> <span class="comment">// If this class or one of its base classes is a PropertyChange</span></div><div class="line"> <span class="comment">// source, then we assume that any properties we discover are "bound".</span></div><div class="line"> <span class="keyword">if</span> (propertyChangeSource) {</div><div class="line"> pd.setBound(<span class="keyword">true</span>);</div><div class="line"> }</div><div class="line"> addPropertyDescriptor(pd);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="comment">//将PropertyDescriptor从pdStore中取出来并处理,填充properties这个Map集合</span></div><div class="line"> processPropertyDescriptors();</div><div class="line"></div><div class="line"> <span class="comment">//最终,将处理过后的properties返回,这就是我们的结果</span></div><div class="line"> <span class="comment">// Allocate and populate the result array.</span></div><div class="line"> PropertyDescriptor result[] =</div><div class="line"> properties.values().toArray(<span class="keyword">new</span> PropertyDescriptor[properties.size()]);</div><div class="line"></div><div class="line"> <span class="comment">// Set the default index.</span></div><div class="line"> <span class="keyword">if</span> (defaultPropertyName != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < result.length; i++) {</div><div class="line"> <span class="keyword">if</span> (defaultPropertyName.equals(result[i].getName())) {</div><div class="line"> defaultPropertyIndex = i;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> result;</div><div class="line">}</div></pre></td></tr></table></figure><p>这个方法很长,但是最终我们找到了关键的地方getTargetPropertyInfo,因此,由于我们的Device类,所有元素都是public,并没有set/get/is/add之类的标准JavaBean所具有的方法,因此这里返回的PropertyDescriptor[]中只有一个Class元素,并不包含任何方法属性pd</p><p>从而导致 int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); 这里,数组内容都是-1,即找不到属性<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <T> <span class="function">T <span class="title">populateBean</span><span class="params">(ResultSet rs, T bean)</span> <span class="keyword">throws</span> SQLException </span>{</div><div class="line"> PropertyDescriptor[] props = <span class="keyword">this</span>.propertyDescriptors(bean.getClass());</div><div class="line"> ResultSetMetaData rsmd = rs.getMetaData();</div><div class="line"> <span class="keyword">int</span>[] columnToProperty = <span class="keyword">this</span>.mapColumnsToProperties(rsmd, props);</div><div class="line"></div><div class="line"> <span class="keyword">return</span> populateBean(rs, bean, props, columnToProperty);</div><div class="line">}</div></pre></td></tr></table></figure></p><p>也就无法填充这个BeanClass的成员内容了,所以最终数据库QueryRunner查询出来的实例内容都是空的</p><h4 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h4><p><a href="https://zh.wikipedia.org/wiki/JavaBeans" target="_blank" rel="external">https://zh.wikipedia.org/wiki/JavaBeans</a></p>]]></content>
<summary type="html">
<p>今天搭建服务器,使用DBUtils处理数据库的时候,出了个小问题:<br><br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="源码阅读" scheme="http://www.molingyu.com/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
<category term="Java" scheme="http://www.molingyu.com/tags/Java/"/>
</entry>
<entry>
<title>前端学习笔记_JavaScript学习(一)</title>
<link href="http://www.molingyu.com/2017/11/09/%E5%89%8D%E7%AB%AF%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0_JavaScript%E5%AD%A6%E4%B9%A0(%E4%B8%80)/"/>
<id>http://www.molingyu.com/2017/11/09/前端学习笔记_JavaScript学习(一)/</id>
<published>2017-11-08T17:22:16.223Z</published>
<updated>2017-11-08T17:22:16.223Z</updated>
<content type="html"><![CDATA[<p>技术成长栈:</p><ol><li>Android</li><li>Java、C/C++</li><li>HTML + CSS + JavaScript</li><li>Spring + Node.js + Vert.x</li><li>产品:Principle、xmind</li></ol><p>这个章节,主要记录下我的JavaScript学习中碰到的问题</p><h2 id="JavaScript中的原型继承模型"><a href="#JavaScript中的原型继承模型" class="headerlink" title="JavaScript中的原型继承模型"></a>JavaScript中的原型继承模型</h2><p>JavaScript中没有类似于Java、C++的类继承机制,JavaScript中的继承通过原型来实现。</p><p>这里的原型,我们可以类比于传统的父类,首先我们要明白:</p><ol><li>所有的对象最终原型都是Object,Object定义了JavaScript世界的通用方法和成员,这点很类似与Java</li><li>当访问JavaScript对象的某个成员时(成员变量或者成员函数),会首先在本对象定义中查找该成员,如果找不到就从直接父原型(<em>proto</em>)中查找,如果还找不到,就因此向上查找,直到最顶端的Object原型,如果还没有找到就报错,这便是原型链查找。</li><li>每个函数都有一个prototype属性,这属性指向当前函数真正所属的对象(即定义它的对象)</li></ol><p>明白了这三点,我们来看下继承的实现,实例代码如下:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//定义构造函数</span></div><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>) </span>{</div><div class="line">}</div><div class="line"><span class="comment">//构造函数原型prototype属性定义及初始化</span></div><div class="line">Person.prototype.name = <span class="string">"Nicholas"</span>;</div><div class="line">Person.prototype.age = <span class="number">29</span>;</div><div class="line">Person.prototype.job = <span class="string">"Software Engineer"</span>;</div><div class="line"><span class="comment">//为Person函数原型prototype定义函数sayName</span></div><div class="line">Person.prototype.sayName = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> alert(<span class="keyword">this</span>.name);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//调用Person构造函数,创建person1对象</span></div><div class="line"><span class="keyword">var</span> person1 = <span class="keyword">new</span> Person();</div><div class="line"><span class="comment">//为实例person1增加name成员,可以通过 delete person1.name;语句来删除person1的name成员</span></div><div class="line">person1.name = <span class="string">"Roket"</span>;</div><div class="line">person1.sayName();</div><div class="line"></div><div class="line"><span class="keyword">var</span> person2 = <span class="keyword">new</span> Person();</div><div class="line">person2.__proto__.name = <span class="string">"Michle"</span>;</div><div class="line"></div><div class="line">person2.sayName();</div><div class="line"></div><div class="line">alert(person1.name === person2.name);</div><div class="line"></div><div class="line">alert(person1.sayName === person2.sayName);</div></pre></td></tr></table></figure></p><p>上述代码中,</p><ul><li>定义了Person构造函数,并给出了空实现</li><li>定义Person的原型:在函数原型对象上定义name、age、job以及sayName成员</li><li>声明var person1、person2两个Person对象,定义的时候调用了Person的空构造函数实例化,实例化完成之后,这两个Person对象,拥有同一个原型。</li><li>person1在本对象内,定义了name成员,并将”Rocket”赋值给了name成员。通过chrome F12 debug工具看到, person1具有name成员,值为”Rokcet”,此时其原型person1.prototype.name的值是”Nicholas”</li><li>person2通过person2.__proto__ 直接访问person2的原型对象,然后将name=”Michle”赋值给原型的name成员。 通过debug看到,person2对象本身没有name成员,其原型person2.prototype.name值被修改为”Michle”,而person1.prototype.name的值也被修改为了”Michle”值。</li><li>根据原型链查找原理:person1.name=”Rockt”, person2.name=”Michle”,但是对于person1.sayName与person2.sayName,他们都是Person.prototype.sayName方法对象,是一个对象。</li></ul><blockquote><p>也就是说,JavaScript中,多个同原型实例会共享原型的所有成员,包括成员函数、成员变量,</p></blockquote><p>因此,为了解决这个问题:</p><ol><li>通常定义对象时都提供构造函数,用来初始化那些对象所私有的成员属性</li><li>而共享的成员、成员函数,都直接共享使用原型中的成员</li></ol><p>这便是我们所说的:组合使用 <figure class="highlight plain"><figcaption><span>和 ```原型模式```</span></figcaption><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div></pre></td><td class="code"><pre><div class="line"></div><div class="line">这是ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。</div><div class="line"></div><div class="line"></div><div class="line">## JavaScript中原型继承一些重要的概念</div><div class="line"></div><div class="line">#### 1. 除了基本数据类型,所有的元素都是对象,函数Function、数组Array、对象Object</div><div class="line"></div><div class="line">Function函数、Array函数、Object函数 以及 null对象,是由JavaScript虚拟机VM内部提供的对象,是一个全局唯一的对象。</div><div class="line"></div><div class="line"></div><div class="line">#### 2. 每个对象都有一个 __proto__ 属性,指向的是创建该对象的那个函数对象(构造函数)的prototype属性</div><div class="line"></div><div class="line">```javascript</div><div class="line">//声明并定义函数对象Fn</div><div class="line">function Fn() { }</div><div class="line">Fn.prototype.name = 'name';</div><div class="line">Fn.prototype.getYear = function () {</div><div class="line"> return 1998;</div><div class="line">};</div><div class="line"></div><div class="line">var fn = new Fn();</div><div class="line">console.log(fn.name);</div><div class="line">console.log(fn.getYear());</div><div class="line">console.log(fn.__proto__ === Fn.prototype);//true</div></pre></td></tr></table></figure></p><p>上面代码中:</p><ol><li>对象fn由函数Fn()创建</li><li>Fn函数的原型 Fn.prototype具有name属性、getYear()函数</li><li>fn.__proto__ === Fn.prototype 为true</li></ol><p>因此,证明本节的论点,也就是说,对象继承于构造函数的prototype,也就是说,对象的原型是构造函数的prototype</p><h4 id="3-每个函数-对象-都有一个-proto-属性,指向函数的构造函数Function对象的prototype属性"><a href="#3-每个函数-对象-都有一个-proto-属性,指向函数的构造函数Function对象的prototype属性" class="headerlink" title="3. 每个函数(对象)都有一个__proto__属性,指向函数的构造函数Function对象的prototype属性:"></a>3. 每个函数(对象)都有一个__proto__属性,指向函数的构造函数Function对象的prototype属性:</h4><p>因为,在JavaScript世界中,函数是一个Function对象,可以通过构造函数Function(…)来创建函数,代码如下<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> fn1 = <span class="function"><span class="keyword">function</span> (<span class="params">x, y</span>) </span>{</div><div class="line"> <span class="keyword">return</span> x + y;</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keyword">var</span> fn2 = <span class="keyword">new</span> <span class="built_in">Function</span>(<span class="string">'x'</span>, <span class="string">'y'</span>, <span class="string">"return x + y"</span>);</div><div class="line"></div><div class="line"><span class="built_in">console</span>.log(fn1(<span class="number">2</span>, <span class="number">2</span>));</div><div class="line"></div><div class="line"><span class="built_in">console</span>.log(fn2(<span class="number">1</span>, <span class="number">2</span>));</div><div class="line"></div><div class="line"><span class="built_in">console</span>.log(fn2.__proto__ === <span class="built_in">Function</span>.prototype);<span class="comment">//true</span></div><div class="line"><span class="built_in">console</span>.log(fn1.__proto__ === <span class="built_in">Function</span>.prototype);<span class="comment">//true</span></div><div class="line"><span class="built_in">console</span>.log(fn2.__proto__ === fn1.__proto__); <span class="comment">//true</span></div></pre></td></tr></table></figure></p><p>根据第二点,所以由Function函数创建的对象fn2的原型 fn2.__proto__ 指向的是构造函数 Function的prototype属性</p><h4 id="4-访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找,这就是原型链。"><a href="#4-访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找,这就是原型链。" class="headerlink" title="4. 访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着proto这条链向上找,这就是原型链。"></a>4. 访问一个对象的属性时,先在基本属性中查找,如果没有,再沿着<strong>proto</strong>这条链向上找,这就是原型链。</h4><p><img src="http://images.cnitblog.com/blog/138012/201409/182013450814552.png" alt=""></p><p>上图中,访问f1.b时,f1的基本属性中没有b,于是沿着__proto__找到了Foo.prototype.b。</p><p><strong><em>判断对象原型链属性的位置的方法</em></strong>:</p><ol><li>使用 hasOwnProperty 来判断对象自身是否有定义属性</li><li>使用 in 操作符,来确定属性是否在原型链上存在</li></ol><p>以下代码可以确定属性是存在与对象中,还是存在于原型中<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">function</span> <span class="title">hasPrototypeProperty</span>(<span class="params">object, popertyName</span>)</span>{</div><div class="line"><span class="keyword">return</span> !object.hasOwnProperty(popertyName) && (popertyName <span class="keyword">in</span> object);</div><div class="line">}</div></pre></td></tr></table></figure></p><h4 id="5-instanceof-的原理"><a href="#5-instanceof-的原理" class="headerlink" title="5. instanceof 的原理"></a>5. instanceof 的原理</h4><ol><li>instanceof 是一个二元运算符: 左侧 是一个普通对象,右侧是一个函数对象 </li><li>instanceof 运算过程: <ol><li>左侧按照原型链查找,即依次追溯左侧对象的__proto__属性</li><li>右侧按照函数的prototype进行查找</li></ol></li><li>两边查找到一个相同对象的引用,则运算结束,返回true,若找不到,则返回false</li></ol><p>例如:<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"><span class="comment"> * instanceof 运算符: 左边的是一个对象,右边的是一个函数</span></div><div class="line"><span class="comment"> * 1. 左边从原型链往前查找</span></div><div class="line"><span class="comment"> * 2. 右边从prototype查找</span></div><div class="line"><span class="comment"> */</span></div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"><span class="comment"> * Object是一个函数对象,它由Function构造函数创建,Object.__proto__ === Function.prototype</span></div><div class="line"><span class="comment"> * Function是一个函数对象,直接找它的prototype,即Function.prototype</span></div><div class="line"><span class="comment"> * 因此,该语句为true</span></div><div class="line"><span class="comment"> */</span></div><div class="line"><span class="built_in">console</span>.log(<span class="built_in">Object</span> <span class="keyword">instanceof</span> <span class="built_in">Function</span>);</div><div class="line"><span class="comment">/**</span></div><div class="line"><span class="comment"> * Function是一个函数对象,它由Function构造函数创建,因此Function.__proto_ == Function.prototype,</span></div><div class="line"><span class="comment"> * 而Function.prototype是一个普通的Object对象,因此Function.prototype.__proto__ == Object.prototype</span></div><div class="line"><span class="comment"> * Object是一个函数对象,直接找它的prototype,即Object.prototype</span></div><div class="line"><span class="comment"> * 因此,语句为true</span></div><div class="line"><span class="comment"> */</span></div><div class="line"><span class="built_in">console</span>.log(<span class="built_in">Function</span> <span class="keyword">instanceof</span> <span class="built_in">Object</span>);</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"><span class="comment"> * Function是一个函数对象,它由Function构造函数创建,因此Function.__proto_ == Function.prototype</span></div><div class="line"><span class="comment"> * Function是一个函数对象,直接找它的prototype,即Function.prototype</span></div><div class="line"><span class="comment"> * 因此,语句为true</span></div><div class="line"><span class="comment"> */</span></div><div class="line"><span class="built_in">console</span>.log(<span class="built_in">Function</span> <span class="keyword">instanceof</span> <span class="built_in">Function</span>);</div></pre></td></tr></table></figure></p><h4 id="6-this指针"><a href="#6-this指针" class="headerlink" title="6. this指针"></a>6. this指针</h4><p>来看代码<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> obj = {</div><div class="line"> x: <span class="number">10</span>,</div><div class="line"> fn: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>);<span class="comment">//此时,this是obj这个对象</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>);<span class="comment">//到这里,this指的是window</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.x);</div><div class="line"> }</div><div class="line"> f();</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line">obj.fn();</div></pre></td></tr></table></figure></p><p>这里 function f()在函数fn内部被定义,但是它是一个普通函数,它并不属于某个对象。因此它的this是window</p><p>再看另外一段代码<br><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"><span class="comment"> * 函数栈帧的概念:</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * 在执行一个函数的时候,JavaScript会为函数做一些准备工作,创建一个栈帧,然后:</span></div><div class="line"><span class="comment"> * 1. 变量声明:</span></div><div class="line"><span class="comment"> * 1)将函数块(域)中出现的变量,声明提升到最前面来,给默认undefined值</span></div><div class="line"><span class="comment"> * 2)如果是自由变量,则往前面的栈帧查找该变量,如果最终到window栈帧都没找到,则在window栈帧默认为该变量声明,赋值undefined</span></div><div class="line"><span class="comment"> * 3)如果是函数表达式,即var fun = function(...){...},则把fun当做普通变量处理,预定义为undefined。</span></div><div class="line"><span class="comment"> * 2. this指针赋值,this可能是window、或者某个对象</span></div><div class="line"><span class="comment"> * 3. 函数声明,即直接在函数块中声明:function fun(...){...},此时,直接声明fun函数,并给它赋值,这个值就指向定义的函数。</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * @type {number}</span></div><div class="line"><span class="comment"> */</span></div><div class="line"><span class="keyword">var</span> x = <span class="number">100</span>;</div><div class="line"></div><div class="line"><span class="keyword">var</span> outer = {</div><div class="line"> x:<span class="number">10</span>,</div><div class="line"> outFun:<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>); <span class="comment">//对象outer</span></div><div class="line"> <span class="built_in">console</span>.log(x); <span class="comment">//this.x 与 x的区别</span></div><div class="line"></div><div class="line"> <span class="keyword">var</span> myfun = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="string">"outer.myfun()"</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">var</span> inner = {</div><div class="line"> x: <span class="number">20</span>,</div><div class="line"> innerFun: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>); <span class="comment">//对象obj</span></div><div class="line"> <span class="built_in">console</span>.log(x); <span class="comment">//this.x 与 x的区别</span></div><div class="line"></div><div class="line"> <span class="comment">//为this添加myfun函数,该函数的调用需要使用obj.myfun()的方式调用</span></div><div class="line"> <span class="keyword">this</span>.myfun = <span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>); <span class="comment">//对象obj</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.x); <span class="comment">//对象obj.x</span></div><div class="line"></div><div class="line"> <span class="function"><span class="keyword">function</span> <span class="title">f</span>(<span class="params"></span>) </span>{</div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>); <span class="comment">//普通函数,window</span></div><div class="line"> <span class="built_in">console</span>.log(<span class="keyword">this</span>.x); <span class="comment">//window没有x定义</span></div><div class="line"> }</div><div class="line"> f();</div><div class="line"></div><div class="line"> };</div><div class="line"> m = <span class="number">1024</span>;</div><div class="line"> <span class="comment">//本栈中无法找到,则向前一个栈帧查找myfun()的定义</span></div><div class="line"> myfun();</div><div class="line"></div><div class="line"> <span class="keyword">var</span> fun = <span class="keyword">this</span>.myfun;</div><div class="line"> fun();</div><div class="line"></div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> inner.innerFun();</div><div class="line"> }</div><div class="line">}</div><div class="line">outer.outFun();</div></pre></td></tr></table></figure></p><p>在这里,function f()被赋值为this.now成员,在调用的时候,采用了this.now()来调用,因此,函数内部的直接this,就是这里的this,也就是obj这个对象。</p><h2 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">var</span> foo = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">var</span> secret = <span class="string">'secret'</span>;</div><div class="line"> <span class="keyword">return</span> {</div><div class="line"> <span class="comment">//内部对象:定义的函数</span></div><div class="line"> get_secret: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>{</div><div class="line"> <span class="keyword">return</span> secret;</div><div class="line"> },</div><div class="line"> new_secret: <span class="function"><span class="keyword">function</span>(<span class="params">newsecret</span>)</span>{</div><div class="line"> secret = newsecret;</div><div class="line"> }</div><div class="line"> };</div><div class="line">}(); <span class="comment">//(),直接调用该函数</span></div><div class="line"></div><div class="line"><span class="comment">//JavaScript中,内部函数作用域,永远都可以访问上层作用域的变量</span></div><div class="line"><span class="comment">//从而导致了,本不能访问var secret变量的此处,可以通过get/new_secret函数来访问</span></div><div class="line"><span class="comment">//并且成员并不会立刻被销毁,只有闭包函数被销毁了,成员secret才会被销毁。</span></div><div class="line"><span class="built_in">console</span>.log(foo.get_secret());</div><div class="line"><span class="built_in">console</span>.log(foo.secret); <span class="comment">//error</span></div><div class="line"><span class="built_in">console</span>.log(foo.new_secret(<span class="string">'a new secret'</span>));</div><div class="line"><span class="built_in">console</span>.log(foo.get_secret());</div></pre></td></tr></table></figure><h1 id="JavaScript-与-Java区别记录:"><a href="#JavaScript-与-Java区别记录:" class="headerlink" title="JavaScript 与 Java区别记录:"></a>JavaScript 与 Java区别记录:</h1><h2 id="1"><a href="#1" class="headerlink" title="1."></a>1.</h2><h2 id="2"><a href="#2" class="headerlink" title="2."></a>2.</h2>]]></content>
<summary type="html">
<p>技术成长栈:</p>
<ol>
<li>Android</li>
<li>Java、C/C++</li>
<li>HTML + CSS + JavaScript</li>
<li>Spring + Node.js + Vert.x</li>
<li>产品:Principle
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="前端" scheme="http://www.molingyu.com/tags/%E5%89%8D%E7%AB%AF/"/>
<category term="JavaScript" scheme="http://www.molingyu.com/tags/JavaScript/"/>
</entry>
<entry>
<title>Android启动源码阅读(三)systemserver进程的启动</title>
<link href="http://www.molingyu.com/2017/09/27/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%B8%89)systemserver%E7%9A%84%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B/"/>
<id>http://www.molingyu.com/2017/09/27/Android启动源码阅读(三)systemserver的启动过程/</id>
<published>2017-09-27T08:24:32.910Z</published>
<updated>2017-09-27T08:24:32.910Z</updated>
<content type="html"><![CDATA[<p>上一篇[zygote进程的启动]我们讲述了<a href="http://molingyu.com/2017/09/27/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%BA%8C)zygote%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%90%AF%E5%8A%A8/#RuntimeInit-zygoteInit" target="_blank" rel="external">zygote进程的启动</a>,以及循环等待client请求的过程。期间,有一段代码,开启了systemserver进程。 现在我们来看下systemserver到底是怎么起起来的。</p><h1 id="进程的创建与启动"><a href="#进程的创建与启动" class="headerlink" title="进程的创建与启动"></a>进程的创建与启动</h1><h2 id="启动源头"><a href="#启动源头" class="headerlink" title="启动源头"></a>启动源头</h2><p>com.android.internal.os.ZygoteInit#main<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">if</span> (startSystemServer) {</div><div class="line"> startSystemServer(abiList, socketName);</div><div class="line">}</div></pre></td></tr></table></figure></p><h2 id="startSystemServer方法"><a href="#startSystemServer方法" class="headerlink" title="startSystemServer方法"></a>startSystemServer方法</h2><p>Zygote.forkSystemServer的执行路径:</p><ol><li>com.android.internal.os.Zygote#nativeForkSystemServer</li><li>frameworks/base/core/jni/com_android_internal_os_Zygote.cpp: com_android_internal_os_Zygote_nativeForkSystemServer</li><li>frameworks/base/core/jni/com_android_internal_os_Zygote.cpp: ForkAndSpecializeCommon</li><li>ForkAndSpecializeCommon: pid_t pid = fork(); //至此,调用fork,创建了新的进程</li></ol><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">startSystemServer</span><span class="params">(String abiList, String socketName)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> MethodAndArgsCaller, RuntimeException </span>{</div><div class="line"> <span class="keyword">long</span> capabilities = posixCapabilitiesAsBits(</div><div class="line"> OsConstants.CAP_IPC_LOCK,</div><div class="line"> OsConstants.CAP_KILL,</div><div class="line"> OsConstants.CAP_NET_ADMIN,</div><div class="line"> OsConstants.CAP_NET_BIND_SERVICE,</div><div class="line"> OsConstants.CAP_NET_BROADCAST,</div><div class="line"> OsConstants.CAP_NET_RAW,</div><div class="line"> OsConstants.CAP_SYS_MODULE,</div><div class="line"> OsConstants.CAP_SYS_NICE,</div><div class="line"> OsConstants.CAP_SYS_PTRACE,</div><div class="line"> OsConstants.CAP_SYS_TIME,</div><div class="line"> OsConstants.CAP_SYS_TTY_CONFIG</div><div class="line"> );</div><div class="line"> <span class="comment">/* Containers run without this capability, so avoid setting it in that case */</span></div><div class="line"> <span class="keyword">if</span> (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, <span class="keyword">false</span>)) {</div><div class="line"> capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);</div><div class="line"> }</div><div class="line"> <span class="comment">/* Hardcoded command line to start the system server */</span></div><div class="line"> String args[] = {</div><div class="line"> <span class="string">"--setuid=1000"</span>, <span class="comment">//设置system_server进程id</span></div><div class="line"> <span class="string">"--setgid=1000"</span>, <span class="comment">//设置system_server进程group id</span></div><div class="line"> <span class="string">"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007,3009,3010"</span>,</div><div class="line"> <span class="string">"--capabilities="</span> + capabilities + <span class="string">","</span> + capabilities,</div><div class="line"> <span class="string">"--nice-name=system_server"</span>, <span class="comment">//设置进程名字</span></div><div class="line"> <span class="string">"--runtime-args"</span>,</div><div class="line"> <span class="string">"com.android.server.SystemServer"</span>, <span class="comment">//进程锁需要执行的class类名</span></div><div class="line"> };</div><div class="line"> ZygoteConnection.Arguments parsedArgs = <span class="keyword">null</span>;</div><div class="line"></div><div class="line"> <span class="keyword">int</span> pid;</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> parsedArgs = <span class="keyword">new</span> ZygoteConnection.Arguments(args);</div><div class="line"> ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);</div><div class="line"> ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);</div><div class="line"></div><div class="line"> <span class="comment">/* Request to fork the system server process */</span></div><div class="line"> pid = Zygote.forkSystemServer(</div><div class="line"> parsedArgs.uid, parsedArgs.gid,</div><div class="line"> parsedArgs.gids,</div><div class="line"> parsedArgs.debugFlags,</div><div class="line"> <span class="keyword">null</span>,</div><div class="line"> parsedArgs.permittedCapabilities,</div><div class="line"> parsedArgs.effectiveCapabilities);</div><div class="line"> } <span class="keyword">catch</span> (IllegalArgumentException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(ex);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/* For child process */</span></div><div class="line"> <span class="keyword">if</span> (pid == <span class="number">0</span>) {</div><div class="line"> <span class="comment">//子进程,即zygote的子进程</span></div><div class="line"> <span class="keyword">if</span> (hasSecondZygote(abiList)) {</div><div class="line"> <span class="comment">//如果有第二个zygote进程,不断的重连第二个zygote进程</span></div><div class="line"> waitForSecondaryZygote(socketName);</div><div class="line"> }</div><div class="line"> <span class="comment">//处理SystemServer</span></div><div class="line"> handleSystemServerProcess(parsedArgs);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="handleSystemServerProcess"><a href="#handleSystemServerProcess" class="headerlink" title="handleSystemServerProcess"></a>handleSystemServerProcess</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">handleSystemServerProcess</span><span class="params">(</span></span></div><div class="line"><span class="function"><span class="params"> ZygoteConnection.Arguments parsedArgs)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> <span class="comment">//systerserver端不需要 sServerSocket,关闭</span></div><div class="line"> closeServerSocket();</div><div class="line"></div><div class="line"> <span class="comment">// set umask to 0077 so new files and directories will default to owner-only permissions.</span></div><div class="line"> Os.umask(S_IRWXG | S_IRWXO);</div><div class="line"></div><div class="line"> <span class="comment">//设置进程名</span></div><div class="line"> <span class="keyword">if</span> (parsedArgs.niceName != <span class="keyword">null</span>) {</div><div class="line"> Process.setArgV0(parsedArgs.niceName);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//获取环境变量SYSTEMSERVERCLASSPATH,环境变量位于init.environ.rc中</span></div><div class="line"> <span class="keyword">final</span> String systemServerClasspath = Os.getenv(<span class="string">"SYSTEMSERVERCLASSPATH"</span>);</div><div class="line"> <span class="comment">////对环境变量SYSTEMSERVERCLASSPATH中的jar包进行dex优化</span></div><div class="line"> <span class="keyword">if</span> (systemServerClasspath != <span class="keyword">null</span>) {</div><div class="line"> performSystemServerDexOpt(systemServerClasspath);</div><div class="line"> }</div><div class="line"> </div><div class="line"> <span class="comment">//systerserver启动参数不包含--invoke-with</span></div><div class="line"> <span class="keyword">if</span> (parsedArgs.invokeWith != <span class="keyword">null</span>) {</div><div class="line"> String[] args = parsedArgs.remainingArgs;</div><div class="line"> <span class="comment">// If we have a non-null system server class path, we'll have to duplicate the</span></div><div class="line"> <span class="comment">// existing arguments and append the classpath to it. ART will handle the classpath</span></div><div class="line"> <span class="comment">// correctly when we exec a new process.</span></div><div class="line"> <span class="keyword">if</span> (systemServerClasspath != <span class="keyword">null</span>) {</div><div class="line"> String[] amendedArgs = <span class="keyword">new</span> String[args.length + <span class="number">2</span>];</div><div class="line"> amendedArgs[<span class="number">0</span>] = <span class="string">"-cp"</span>;</div><div class="line"> amendedArgs[<span class="number">1</span>] = systemServerClasspath;</div><div class="line"> System.arraycopy(parsedArgs.remainingArgs, <span class="number">0</span>, amendedArgs, <span class="number">2</span>, parsedArgs.remainingArgs.length);</div><div class="line"> }</div><div class="line"></div><div class="line"> WrapperInit.execApplication(parsedArgs.invokeWith,</div><div class="line"> parsedArgs.niceName, parsedArgs.targetSdkVersion,</div><div class="line"> VMRuntime.getCurrentInstructionSet(), <span class="keyword">null</span>, args);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> ClassLoader cl = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">if</span> (systemServerClasspath != <span class="keyword">null</span>) {</div><div class="line"> cl = createSystemServerClassLoader(systemServerClasspath,</div><div class="line"> parsedArgs.targetSdkVersion);</div><div class="line"></div><div class="line"> Thread.currentThread().setContextClassLoader(cl);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * Pass the remaining arguments to SystemServer.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="comment">//最终调用到RuntimeInit.zygoteInit,并传参parsedArgs.remainingArgs = "com.android.server.SystemServer"</span></div><div class="line"> RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/* should never reach here */</span></div><div class="line">}</div></pre></td></tr></table></figure><p>最终调用到RuntimeInit.zygoteInit,在上篇<a href="http://molingyu.com/2017/09/27/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%BA%8C)zygote%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%90%AF%E5%8A%A8/#RuntimeInit-zygoteInit" target="_blank" rel="external">zygote进程的启动</a>讲述过</p><h1 id="SystemServer-main-的执行情况:"><a href="#SystemServer-main-的执行情况:" class="headerlink" title="SystemServer.main()的执行情况:"></a>SystemServer.main()的执行情况:</h1>]]></content>
<summary type="html">
<p>上一篇[zygote进程的启动]我们讲述了<a href="http://molingyu.com/2017/09/27/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%BA%8C)zygo
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Android" scheme="http://www.molingyu.com/tags/Android/"/>
<category term="源码阅读" scheme="http://www.molingyu.com/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
</entry>
<entry>
<title>Android启动源码阅读(二)zygote进程的启动</title>
<link href="http://www.molingyu.com/2017/09/27/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%BA%8C)zygote%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%90%AF%E5%8A%A8/"/>
<id>http://www.molingyu.com/2017/09/27/Android启动源码阅读(二)zygote进程的启动/</id>
<published>2017-09-26T21:04:22.273Z</published>
<updated>2017-09-26T21:04:22.273Z</updated>
<content type="html"><![CDATA[<p>从上一篇<a href="http://molingyu.com/2017/09/26/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%B8%80)init%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%90%AF%E5%8A%A8/" target="_blank" rel="external">init的启动</a>可以看到,zygote由init进程解析init.zygoteXXX.rc文件,然后fork进程,并为zygote进程创建了/dev/socket/zygote的socket接口,然后创建zygote进程,执行/system/bin/app_process,传入参数:-Xzygote /system/bin –zygote –start-system-server</p><p>本文,我们看下app_process干了些什么事情</p><p>仍然是AndroidStudio查找源码的流程:</p><ol><li>Ctrl + Shift + F 全局查找字符串 <em>:= app_process</em></li><li>找到Android.mk文件:frameworks/base/cmds/app_process/Android.mk</li><li>对应的LOCAL_SRC_FILES:= \app_main.cpp,因此app_process的源码位于frameworks/base/cmds/app_process/app_main.cpp中</li></ol><h1 id="开始阅读-app-main-cpp-gt-main-方法"><a href="#开始阅读-app-main-cpp-gt-main-方法" class="headerlink" title="开始阅读:app_main.cpp -> main()方法"></a>开始阅读:app_main.cpp -> main()方法</h1><p>记住,在init在执行的时候,入参是:-Xzygote /system/bin –zygote –start-system-server,解析得到的args = {“-Xzygote” “/system/bin”,”-zygote“, ”-start-system-server“},携带这些参数,我们来看下main方法的执行情况</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//使用argv[0]参数进行</span></div><div class="line">AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));</div><div class="line"><span class="comment">// Process command line arguments</span></div><div class="line"><span class="comment">// ignore argv[0], 忽略argv[0]参数</span></div><div class="line"><span class="comment">//argc-1 = 3</span></div><div class="line">argc--;</div><div class="line"><span class="comment">//argv++,即数组头指针后移一个位置</span></div><div class="line">argv++;</div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="keyword">int</span> i;</div><div class="line"><span class="keyword">for</span> (i = <span class="number">0</span>; i < argc; i++) {</div><div class="line"> <span class="comment">//如果参数不是以'-'开头,直接跳出循环</span></div><div class="line"> <span class="keyword">if</span> (argv[i][<span class="number">0</span>] != <span class="string">'-'</span>) {</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//如果参数第二个字符为'-'并且第三个字符为截止字符,则忽略,并跳出循环</span></div><div class="line"> <span class="keyword">if</span> (argv[i][<span class="number">1</span>] == <span class="string">'-'</span> && argv[i][<span class="number">2</span>] == <span class="number">0</span>) {</div><div class="line"> ++i; <span class="comment">// Skip --.</span></div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//为runtime添加参数</span></div><div class="line"> runtime.addOption(strdup(argv[i]));</div><div class="line">}</div><div class="line"><span class="comment">//因此,因为此前的argv++,故而argv[0]="/syste/bin",故而跳出上述循环,此时i = 0</span></div><div class="line"></div><div class="line">...</div><div class="line"></div><div class="line"><span class="comment">//++i,跳过了第一个参数/system/bin,即跳过父目录参数</span></div><div class="line">++i; <span class="comment">// Skip unused "parent dir" argument.</span></div><div class="line"><span class="comment">//继续执行</span></div><div class="line"><span class="keyword">while</span> (i < argc) {</div><div class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* arg = argv[i++];</div><div class="line"> <span class="comment">//i = 1, argv[1] = "--zygote", 然后i++</span></div><div class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(arg, <span class="string">"--zygote"</span>) == <span class="number">0</span>) {</div><div class="line"> zygote = <span class="literal">true</span>;</div><div class="line"> niceName = ZYGOTE_NICE_NAME;</div><div class="line"> <span class="comment">//i = 1, argv[2] = "-start-system-server", 然后i++=3 = argc,跳出循环</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(arg, <span class="string">"--start-system-server"</span>) == <span class="number">0</span>) {</div><div class="line"> startSystemServer = <span class="literal">true</span>;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(arg, <span class="string">"--application"</span>) == <span class="number">0</span>) {</div><div class="line"> application = <span class="literal">true</span>;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(arg, <span class="string">"--nice-name="</span>, <span class="number">12</span>) == <span class="number">0</span>) {</div><div class="line"> niceName.setTo(arg + <span class="number">12</span>);</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">strncmp</span>(arg, <span class="string">"--"</span>, <span class="number">2</span>) != <span class="number">0</span>) {</div><div class="line"> className.setTo(arg);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> --i;</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="comment">//因此上述while做了几个事情:</span></div><div class="line"><span class="comment">//1. zygote = true;</span></div><div class="line"><span class="comment">//2. niceName = ZYGOTE_NICE_NAME; // zygote或者zygote64</span></div><div class="line"><span class="comment">//3. startSystemServer = true;</span></div><div class="line"></div><div class="line"><span class="comment">//下面代码的注释已经比较清除了,args是runtime.start()要传入的参数之一</span></div><div class="line">Vector<String8> args;</div><div class="line"><span class="keyword">if</span> (!className.isEmpty()) {</div><div class="line"> <span class="comment">// We're not in zygote mode, the only argument we need to pass</span></div><div class="line"> <span class="comment">// to RuntimeInit is the application argument.</span></div><div class="line"> <span class="comment">//</span></div><div class="line"> <span class="comment">// The Remainder of args get passed to startup class main(). Make</span></div><div class="line"> <span class="comment">// copies of them before we overwrite them with the process name.</span></div><div class="line"> args.add(application ? String8(<span class="string">"application"</span>) : String8(<span class="string">"tool"</span>));</div><div class="line"> runtime.setClassNameAndArgs(className, argc - i, argv + i);</div><div class="line">} <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// We're in zygote mode.</span></div><div class="line"> maybeCreateDalvikCache();</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (startSystemServer) {</div><div class="line"> args.add(String8(<span class="string">"start-system-server"</span>));</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">char</span> prop[PROP_VALUE_MAX];</div><div class="line"> <span class="keyword">if</span> (property_get(ABI_LIST_PROPERTY, prop, <span class="literal">NULL</span>) == <span class="number">0</span>) {</div><div class="line"> LOG_ALWAYS_FATAL(<span class="string">"app_process: Unable to determine ABI list from property %s."</span>,</div><div class="line"> ABI_LIST_PROPERTY);</div><div class="line"> <span class="keyword">return</span> <span class="number">11</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="function">String8 <span class="title">abiFlag</span><span class="params">(<span class="string">"--abi-list="</span>)</span></span>;</div><div class="line"> abiFlag.append(prop);</div><div class="line"> args.add(abiFlag);</div><div class="line"></div><div class="line"> <span class="comment">// In zygote mode, pass all remaining arguments to the zygote</span></div><div class="line"> <span class="comment">// main() method.</span></div><div class="line"> <span class="keyword">for</span> (; i < argc; ++i) {</div><div class="line"> args.add(String8(argv[i]));</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//设置进程名称</span></div><div class="line"><span class="keyword">if</span> (!niceName.isEmpty()) {</div><div class="line"> runtime.setArgv0(niceName.<span class="built_in">string</span>());</div><div class="line"> set_process_name(niceName.<span class="built_in">string</span>());</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">if</span> (zygote) {</div><div class="line"> <span class="comment">//进入AppRuntime.start方法</span></div><div class="line"> runtime.start(<span class="string">"com.android.internal.os.ZygoteInit"</span>, args, zygote);</div><div class="line">} <span class="keyword">else</span> <span class="keyword">if</span> (className) {</div><div class="line"> runtime.start(<span class="string">"com.android.internal.os.RuntimeInit"</span>, args, zygote);</div><div class="line">} <span class="keyword">else</span> {</div><div class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Error: no class name or --zygote supplied.\n"</span>);</div><div class="line"> app_usage();</div><div class="line"> LOG_ALWAYS_FATAL(<span class="string">"app_process: no class name or --zygote supplied."</span>);</div><div class="line"> <span class="keyword">return</span> <span class="number">10</span>;</div><div class="line">}</div></pre></td></tr></table></figure><h1 id="AppRuntime-gt-start-方法"><a href="#AppRuntime-gt-start-方法" class="headerlink" title="AppRuntime->start()方法"></a>AppRuntime->start()方法</h1><p>AppRuntime的定义在app_main.cpp中,继承于AndroidRuntime类,类文件位于frameworks/base/core/jni/AndroidRuntime.cpp,头文件位于frameworks/base/include/android_runtime/AndroidRuntime.h</p><p>而AppRuntime主要重写了几个方法:</p><ul><li>onVmCreated</li><li>onStarted</li><li>onZygoteInit</li><li>onExit</li><li>并定义了方法setClassNameAndArgs</li><li>新增了几个成员:String8 mClassName, Vector<string8> mArgs, jclass mClass;</string8></li></ul><p>start方法位于AndroidRuntime中定义,我们来看看:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> AndroidRuntime::start(<span class="keyword">const</span> <span class="keyword">char</span>* className, <span class="keyword">const</span> Vector<String8>& options, <span class="keyword">bool</span> zygote)</div><div class="line">{</div><div class="line"> <span class="comment">//startSystemServer = "start-system-server"</span></div><div class="line"> <span class="function"><span class="keyword">static</span> <span class="keyword">const</span> String8 <span class="title">startSystemServer</span><span class="params">(<span class="string">"start-system-server"</span>)</span></span>;</div><div class="line"></div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="comment">//将rootDir设置为"/system"</span></div><div class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* rootDir = getenv(<span class="string">"ANDROID_ROOT"</span>);</div><div class="line"></div><div class="line"></div><div class="line"> <span class="comment">//1. 启动虚拟机</span></div><div class="line"> <span class="comment">/* start the virtual machine */</span></div><div class="line"> JniInvocation jni_invocation;</div><div class="line"> jni_invocation.Init(<span class="literal">NULL</span>);</div><div class="line"> JNIEnv* env; <span class="comment">//虚拟机环境指针</span></div><div class="line"> <span class="keyword">if</span> (startVm(&mJavaVM, &env, zygote) != <span class="number">0</span>) {</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> onVmCreated(env);</div><div class="line"> </div><div class="line"> <span class="comment">//注册jni函数</span></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * Register android functions.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">if</span> (startReg(env) < <span class="number">0</span>) {</div><div class="line"> ALOGE(<span class="string">"Unable to register all android natives\n"</span>);</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * We want to call main() with a String array with arguments in it.</span></div><div class="line"><span class="comment"> * At present we have two arguments, the class name and an option string.</span></div><div class="line"><span class="comment"> * Create an array to hold them.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> jclass stringClass;</div><div class="line"> jobjectArray strArray;</div><div class="line"> jstring classNameStr;</div><div class="line"></div><div class="line"> stringClass = env->FindClass(<span class="string">"java/lang/String"</span>);</div><div class="line"> assert(stringClass != <span class="literal">NULL</span>);</div><div class="line"> strArray = env->NewObjectArray(options.size() + <span class="number">1</span>, stringClass, <span class="literal">NULL</span>);</div><div class="line"> assert(strArray != <span class="literal">NULL</span>);</div><div class="line"> classNameStr = env->NewStringUTF(className);</div><div class="line"> assert(classNameStr != <span class="literal">NULL</span>);</div><div class="line"> env->SetObjectArrayElement(strArray, <span class="number">0</span>, classNameStr);</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">size_t</span> i = <span class="number">0</span>; i < options.size(); ++i) {</div><div class="line"> jstring optionsStr = env->NewStringUTF(options.itemAt(i).<span class="built_in">string</span>());</div><div class="line"> assert(optionsStr != <span class="literal">NULL</span>);</div><div class="line"> env->SetObjectArrayElement(strArray, i + <span class="number">1</span>, optionsStr);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * Start VM.</span></div><div class="line"><span class="comment"> * 注意以下两点</span></div><div class="line"><span class="comment"> * 1. This thread becomes the main thread of the VM, </span></div><div class="line"><span class="comment"> * 2. and will not return until the VM exits.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">char</span>* slashClassName = toSlashClassName(className);</div><div class="line"> <span class="comment">//找到class字节码实例:com.android.internal.os.ZygoteInit.class</span></div><div class="line"> jclass startClass = env->FindClass(slashClassName);</div><div class="line"> <span class="keyword">if</span> (startClass == <span class="literal">NULL</span>) {</div><div class="line"> ALOGE(<span class="string">"JavaVM unable to locate class '%s'\n"</span>, slashClassName);</div><div class="line"> <span class="comment">/* keep going */</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//找到main函数</span></div><div class="line"> jmethodID startMeth = env->GetStaticMethodID(startClass, <span class="string">"main"</span>, <span class="string">"([Ljava/lang/String;)V"</span>);</div><div class="line"> <span class="keyword">if</span> (startMeth == <span class="literal">NULL</span>) {</div><div class="line"> ALOGE(<span class="string">"JavaVM unable to find main() in '%s'\n"</span>, className);</div><div class="line"> <span class="comment">/* keep going */</span></div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//调用main函数,进入ZygoteInit.main()中,直到main函数退出(此时虚拟机也会退出)</span></div><div class="line"> env->CallStaticVoidMethod(startClass, startMeth, strArray);</div><div class="line"></div><div class="line"><span class="meta">#<span class="meta-keyword">if</span> 0</span></div><div class="line"> <span class="comment">//未正常退出</span></div><div class="line"> <span class="keyword">if</span> (env->ExceptionCheck())</div><div class="line"> threadExitUncaughtException(env);</div><div class="line"><span class="meta">#<span class="meta-keyword">endif</span></span></div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="built_in">free</span>(slashClassName);</div><div class="line"> <span class="comment">//虚拟机退出</span></div><div class="line"> ALOGD(<span class="string">"Shutting down VM\n"</span>);</div><div class="line"> <span class="keyword">if</span> (mJavaVM->DetachCurrentThread() != JNI_OK)</div><div class="line"> ALOGW(<span class="string">"Warning: unable to detach main thread\n"</span>);</div><div class="line"> <span class="keyword">if</span> (mJavaVM->DestroyJavaVM() != <span class="number">0</span>)</div><div class="line"> ALOGW(<span class="string">"Warning: VM did not shut down cleanly\n"</span>);</div><div class="line">}</div></pre></td></tr></table></figure><p>其中:</p><ul><li>startVm(): 一系列的虚拟机环境参数配置,最终调用JNI_CreateJavaVM初始化虚拟机,如果方法调用成功,则虚拟机准备完毕,这部分是dalvikVm的知识,以后再研究</li><li>startReg(): 主要通过register_jni_procs来注册jni函数,如register_com_android_internal_os_RuntimeInit、register_android_opengl<em>jni</em>…等等jni library</li></ul><h1 id="启动虚拟机之后,进入Java世界-ZygoteInit-main"><a href="#启动虚拟机之后,进入Java世界-ZygoteInit-main" class="headerlink" title="启动虚拟机之后,进入Java世界: ZygoteInit.main()"></a>启动虚拟机之后,进入Java世界: ZygoteInit.main()</h1><p>还是来看代码, </p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String argv[])</span> </span>{</div><div class="line"> <span class="comment">// Mark zygote start. This ensures that thread creation will throw</span></div><div class="line"> <span class="comment">// an error.</span></div><div class="line"> ZygoteHooks.startZygoteNoThreadCreation();</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//调试相关</span></div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"ZygoteInit"</span>);</div><div class="line"> /开启ddms</div><div class="line"> RuntimeInit.enableDdms();</div><div class="line"> <span class="comment">// Start profiling the zygote initialization.</span></div><div class="line"> SamplingProfilerIntegration.start();</div><div class="line"> </div><div class="line"> </div><div class="line"> boolean startSystemServer = <span class="literal">false</span>;</div><div class="line"> String socketName = <span class="string">"zygote"</span>;</div><div class="line"> String abiList = null;</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < argv.length; i++) {</div><div class="line"> <span class="comment">//是否需要启动systemserver: zygote进程启动时候,true</span></div><div class="line"> <span class="keyword">if</span> (<span class="string">"start-system-server"</span>.equals(argv[i])) {</div><div class="line"> startSystemServer = <span class="literal">true</span>;</div><div class="line"> <span class="comment">//是否包含abilist,zygote进程,true</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (argv[i].startsWith(ABI_LIST_ARG)) {</div><div class="line"> abiList = argv[i].substring(ABI_LIST_ARG.length());</div><div class="line"> <span class="comment">//是否包含socketname,zygote进程,true</span></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (argv[i].startsWith(SOCKET_NAME_ARG)) {</div><div class="line"> socketName = argv[i].substring(SOCKET_NAME_ARG.length());</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"Unknown command line argument: "</span> + argv[i]);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (abiList == null) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"No ABI list supplied."</span>);</div><div class="line"> }</div><div class="line"> <span class="comment">//注册zygote的socket服务端接口</span></div><div class="line"> registerZygoteSocket(socketName);</div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"ZygotePreload"</span>);</div><div class="line"> EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,</div><div class="line"> SystemClock.uptimeMillis());</div><div class="line"> <span class="comment">//预加载:类、资源、opengl已经共享库等等,这样在fork一个新的进程的时,就不再需要重新加载这些资源</span></div><div class="line"> <span class="comment">//而由于linux的fork机制,这些预加载的资源,除非有修改需求,否则都共享父进程的同一个资源</span></div><div class="line"> preload();</div><div class="line"> EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,</div><div class="line"> SystemClock.uptimeMillis());</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"></div><div class="line"> <span class="comment">// Finish profiling the zygote initialization.</span></div><div class="line"> SamplingProfilerIntegration.writeZygoteSnapshot();</div><div class="line"></div><div class="line"> <span class="comment">// Do an initial gc to clean up after startup</span></div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_DALVIK, <span class="string">"PostZygoteInitGC"</span>);</div><div class="line"> <span class="comment">//进行依次gc回收</span></div><div class="line"> gcAndFinalize();</div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"></div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_DALVIK);</div><div class="line"></div><div class="line"> <span class="comment">// Disable tracing so that forked processes do not inherit stale tracing tags from</span></div><div class="line"> <span class="comment">// Zygote.</span></div><div class="line"> Trace.setTracingEnabled(<span class="literal">false</span>);</div><div class="line"></div><div class="line"> <span class="comment">// Zygote process unmounts root storage spaces.</span></div><div class="line"> Zygote.nativeUnmountStorageOnInit();</div><div class="line"></div><div class="line"> ZygoteHooks.stopZygoteNoThreadCreation();</div><div class="line"> </div><div class="line"> <span class="comment">//启动SystemServer进程</span></div><div class="line"> <span class="keyword">if</span> (startSystemServer) {</div><div class="line"> startSystemServer(abiList, socketName);</div><div class="line"> }</div><div class="line"></div><div class="line"> Log.i(TAG, <span class="string">"Accepting command socket connections"</span>);</div><div class="line"> <span class="comment">//进入select loop循环</span></div><div class="line"> runSelectLoop(abiList);</div><div class="line"> <span class="comment">//关闭服务端server socket</span></div><div class="line"> closeServerSocket();</div><div class="line"> } <span class="keyword">catch</span> (MethodAndArgsCaller caller) {</div><div class="line"> <span class="comment">//caller.run()</span></div><div class="line"> caller.run();</div><div class="line"> } <span class="keyword">catch</span> (Throwable ex) {</div><div class="line"> Log.e(TAG, <span class="string">"Zygote died with exception"</span>, ex);</div><div class="line"> closeServerSocket();</div><div class="line"> <span class="keyword">throw</span> ex;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>小结,ZygoteInit.main()主要做了几件事情:</p><ol><li>registerZygoteSocket,注册zygote的socket服务,等待其他client的请求</li><li>startSystemServer开启systemserver进程,这是java世界的基石:包含了众多的服务,如AMS, WMS,IMS等等</li><li>调用runSelectLoop,进入无限循环,等待client请求,来创建进程,每创建一个进程,在子进程中都会抛出异常MethodAndArgsCaller,从而子进程中的代码会运行到caller.run()方法中去</li></ol><h2 id="1-registerZygoteSocket"><a href="#1-registerZygoteSocket" class="headerlink" title="1. registerZygoteSocket()"></a>1. registerZygoteSocket()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//入参是"zygote"</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">registerZygoteSocket</span><span class="params">(String socketName)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (sServerSocket == <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">int</span> fileDesc;</div><div class="line"> <span class="comment">//由于zygote进程创建的时候,会创建名为zygote的socket节点的fd,并将节点设置到环境变量ANDROID_SOCKET_zygote中去</span></div><div class="line"> <span class="keyword">final</span> String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> String env = System.getenv(fullSocketName);</div><div class="line"> fileDesc = Integer.parseInt(env);</div><div class="line"> } <span class="keyword">catch</span> (RuntimeException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(fullSocketName + <span class="string">" unset or invalid"</span>, ex);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> FileDescriptor fd = <span class="keyword">new</span> FileDescriptor();</div><div class="line"> fd.setInt$(fileDesc);</div><div class="line"> <span class="comment">//创建socket的server端</span></div><div class="line"> sServerSocket = <span class="keyword">new</span> LocalServerSocket(fd);</div><div class="line"> } <span class="keyword">catch</span> (IOException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line"> <span class="string">"Error binding to local socket '"</span> + fileDesc + <span class="string">"'"</span>, ex);</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="2-startSystemServer"><a href="#2-startSystemServer" class="headerlink" title="2. startSystemServer()"></a>2. startSystemServer()</h2><p>另外开一篇文章来写吧,这里我们记住,system_server进程,由zygote进程fork出来,然后在创建的虚拟机中执行SystemServer.main()方法</p><h2 id="3-runSelectLoop"><a href="#3-runSelectLoop" class="headerlink" title="3. runSelectLoop()"></a>3. runSelectLoop()</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">runSelectLoop</span><span class="params">(String abiList)</span> <span class="keyword">throws</span> MethodAndArgsCaller </span>{</div><div class="line"> <span class="comment">//fds和peers一一对应</span></div><div class="line"> ArrayList<FileDescriptor> fds = <span class="keyword">new</span> ArrayList<FileDescriptor>();</div><div class="line"> ArrayList<ZygoteConnection> peers = <span class="keyword">new</span> ArrayList<ZygoteConnection>();</div><div class="line"> </div><div class="line"> <span class="comment">//服务端的fd对应着null值</span></div><div class="line"> fds.add(sServerSocket.getFileDescriptor());</div><div class="line"> peers.add(<span class="keyword">null</span>);</div><div class="line"> </div><div class="line"> <span class="comment">//进入无限循环, 采用 多路复用机制 + socket配合 进行阻塞等待client的请求</span></div><div class="line"> <span class="keyword">while</span> (<span class="keyword">true</span>) {</div><div class="line"> <span class="comment">//监听所有的fd的POLLIN请求,即监听socket可读事件</span></div><div class="line"> StructPollfd[] pollFds = <span class="keyword">new</span> StructPollfd[fds.size()];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < pollFds.length; ++i) {</div><div class="line"> pollFds[i] = <span class="keyword">new</span> StructPollfd();</div><div class="line"> <span class="comment">////pollFds[0]即为fds[0],也就是sServerSocket.fd</span></div><div class="line"> <span class="comment">//1. 一开始,zygote刚启动的时候,这个fds只有sServerSocket.fd一个元素</span></div><div class="line"> <span class="comment">//2. 当有新的client连接sServerSocket时候,就会触发sServerSocket.fd的POLLIN事件</span></div><div class="line"> <span class="comment">//3. 从而导致后面for循环中,i==0成立,然后往peers中新加一个peers,以及往fds列表中添加客户端的fd</span></div><div class="line"> pollFds[i].fd = fds.get(i);</div><div class="line"> pollFds[i].events = (<span class="keyword">short</span>) POLLIN;</div><div class="line"> }</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="comment">//开始poll系统调用,监听多个文件的POLLIN事件,阻塞。 当有事件来临时,继续往下执行</span></div><div class="line"> Os.poll(pollFds, -<span class="number">1</span>);</div><div class="line"> } <span class="keyword">catch</span> (ErrnoException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"poll failed"</span>, ex);</div><div class="line"> }</div><div class="line"> <span class="comment">//遍历所有监控的fd,如果不存在POLLIN事件,则continue跳过该fd,否则执行后面的操作</span></div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = pollFds.length - <span class="number">1</span>; i >= <span class="number">0</span>; --i) {</div><div class="line"> <span class="keyword">if</span> ((pollFds[i].revents & POLLIN) == <span class="number">0</span>) {</div><div class="line"> <span class="keyword">continue</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (i == <span class="number">0</span>) {</div><div class="line"> <span class="comment">//i=0,说明是zygote进程的server端的socket,因此调用socket.accept,获取与客户端的链接,从而拿到fd</span></div><div class="line"> ZygoteConnection newPeer = acceptCommandPeer(abiList);</div><div class="line"> peers.add(newPeer);</div><div class="line"> <span class="comment">//添加到fds列表</span></div><div class="line"> fds.add(newPeer.getFileDesciptor());</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//处理客户端链接</span></div><div class="line"> <span class="keyword">boolean</span> done = peers.get(i).runOnce();</div><div class="line"> <span class="comment">//处理完毕,将fd和peers删除</span></div><div class="line"> <span class="keyword">if</span> (done) {</div><div class="line"> peers.remove(i);</div><div class="line"> fds.remove(i);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><ol><li>开启sServerSocket,等待客户端请求</li><li>客户端请求来临,调用ZygoteConnection.runOnce()处理请求</li></ol><h3 id="调用ZygoteConnection-runOnce-处理请求"><a href="#调用ZygoteConnection-runOnce-处理请求" class="headerlink" title="调用ZygoteConnection.runOnce()处理请求"></a>调用ZygoteConnection.runOnce()处理请求</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">runOnce</span><span class="params">()</span> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//读取client端入参列表</span></div><div class="line"> args = readArgumentList();</div><div class="line"> </div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="keyword">int</span> pid = -<span class="number">1</span>;</div><div class="line"> </div><div class="line"> ...</div><div class="line"> <span class="comment">//fork进程</span></div><div class="line"> pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,</div><div class="line"> parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,</div><div class="line"> parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,</div><div class="line"> parsedArgs.appDataDir);</div><div class="line"></div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">if</span> (pid == <span class="number">0</span>) {</div><div class="line"> <span class="comment">// in child</span></div><div class="line"> IoUtils.closeQuietly(serverPipeFd);</div><div class="line"> serverPipeFd = <span class="keyword">null</span>;</div><div class="line"> handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);</div><div class="line"></div><div class="line"> <span class="comment">// should never get here, the child is expected to either</span></div><div class="line"> <span class="comment">// throw ZygoteInit.MethodAndArgsCaller or exec().</span></div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">// in parent...pid of < 0 means failure</span></div><div class="line"> IoUtils.closeQuietly(childPipeFd);</div><div class="line"> childPipeFd = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">return</span> handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);</div><div class="line"> }</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> IoUtils.closeQuietly(childPipeFd);</div><div class="line"> IoUtils.closeQuietly(serverPipeFd);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="handleChildProc-与-handleParentProc"><a href="#handleChildProc-与-handleParentProc" class="headerlink" title="handleChildProc 与 handleParentProc"></a>handleChildProc 与 handleParentProc</h3><p>首先来看 handleChildProc,即zygote进程fork出来的子进程执行的方法<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleChildProc</span><span class="params">(Arguments parsedArgs,</span></span></div><div class="line"><span class="function"><span class="params"> FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * By the time we get here, the native code has closed the two actual Zygote</span></div><div class="line"><span class="comment"> * socket connections, and substituted /dev/null in their place. The LocalSocket</span></div><div class="line"><span class="comment"> * objects still need to be closed properly.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> </div><div class="line"> <span class="comment">//子进程不再需要处理socket请求,因此关掉两端</span></div><div class="line"> closeSocket();</div><div class="line"> ZygoteInit.closeServerSocket();</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//子进程名字的设置</span></div><div class="line"> <span class="keyword">if</span> (parsedArgs.niceName != <span class="keyword">null</span>) {</div><div class="line"> Process.setArgV0(parsedArgs.niceName);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// End of the postFork event.</span></div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line"> <span class="comment">//如果定义了invokeWith参数,则采用 /system/bin/sh这种execShell的方式执行command</span></div><div class="line"> <span class="keyword">if</span> (parsedArgs.invokeWith != <span class="keyword">null</span>) {</div><div class="line"> WrapperInit.execApplication(parsedArgs.invokeWith,</div><div class="line"> parsedArgs.niceName, parsedArgs.targetSdkVersion,</div><div class="line"> VMRuntime.getCurrentInstructionSet(),</div><div class="line"> pipeFd, parsedArgs.remainingArgs);</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">//否则调用zygoteInit,执行初始化</span></div><div class="line"> RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,</div><div class="line"> parsedArgs.remainingArgs, <span class="keyword">null</span> <span class="comment">/* classLoader */</span>);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p><h3 id="RuntimeInit-zygoteInit"><a href="#RuntimeInit-zygoteInit" class="headerlink" title="RuntimeInit.zygoteInit"></a>RuntimeInit.zygoteInit</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">zygoteInit</span><span class="params">(<span class="keyword">int</span> targetSdkVersion, String[] argv, ClassLoader classLoader)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> <span class="keyword">if</span> (DEBUG) Slog.d(TAG, <span class="string">"RuntimeInit: Starting application from zygote"</span>);</div><div class="line"></div><div class="line"> Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="string">"RuntimeInit"</span>);</div><div class="line"> <span class="comment">//log重定向</span></div><div class="line"> redirectLogStreams();</div><div class="line"> </div><div class="line"> <span class="comment">//通用初始化:default UncaughtExceptionHandler、TimeZone、userAgent、NetworkManagementSocketTagger、trace等等</span></div><div class="line"> commonInit();</div><div class="line"> </div><div class="line"> <span class="comment">//调用frameworks/base/core/jni/AndroidRuntime.cpp</span></div><div class="line"> <span class="comment">//最终调用gCurRuntime->onZygoteInit,其中gCurRuntime是在zygote进程执行app_main.cpp->main()时创建的,</span></div><div class="line"> <span class="comment">//而新fork出来的子进程都是基于zygote进程的,因此也会存在该实例</span></div><div class="line"> <span class="comment">//调用AndroidRuntime.onZygoteInit()方法,与binder交互</span></div><div class="line"> nativeZygoteInit();</div><div class="line"> <span class="comment">//应用初始化</span></div><div class="line"> applicationInit(targetSdkVersion, argv, classLoader);</div><div class="line">}</div></pre></td></tr></table></figure><p>startThreadPool方法的调用, 参考链接:<a href="http://blog.csdn.net/ganyue803/article/details/41484849" target="_blank" rel="external">http://blog.csdn.net/ganyue803/article/details/41484849</a><br><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">virtual</span> <span class="keyword">void</span> <span class="title">onZygoteInit</span><span class="params">()</span></span></div><div class="line"><span class="function"></span>{</div><div class="line"> <span class="comment">//binder交互</span></div><div class="line"> sp<ProcessState> proc = ProcessState::self();</div><div class="line"> ALOGV(<span class="string">"App process: starting thread pool.\n"</span>);</div><div class="line"> <span class="comment">//开启主线程,并与binder 最终talkWithDriver()</span></div><div class="line"> proc->startThreadPool();</div><div class="line">}</div></pre></td></tr></table></figure></p><h3 id="RuntimeInit-applicationInit"><a href="#RuntimeInit-applicationInit" class="headerlink" title="RuntimeInit.applicationInit"></a>RuntimeInit.applicationInit</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">applicationInit</span><span class="params">(<span class="keyword">int</span> targetSdkVersion, String[] argv, ClassLoader classLoader)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> <span class="comment">// If the application calls System.exit(), terminate the process</span></div><div class="line"> <span class="comment">// immediately without running any shutdown hooks. It is not possible to</span></div><div class="line"> <span class="comment">// shutdown an Android application gracefully. Among other things, the</span></div><div class="line"> <span class="comment">// Android runtime shutdown hooks close the Binder driver, which can cause</span></div><div class="line"> <span class="comment">// leftover running threads to crash before the process actually exits.</span></div><div class="line"> nativeSetExitWithoutCleanup(<span class="keyword">true</span>);</div><div class="line"></div><div class="line"> <span class="comment">// We want to be fairly aggressive about heap utilization, to avoid</span></div><div class="line"> <span class="comment">// holding on to a lot of memory that isn't needed.</span></div><div class="line"> VMRuntime.getRuntime().setTargetHeapUtilization(<span class="number">0.75f</span>);</div><div class="line"> VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);</div><div class="line"></div><div class="line"> <span class="keyword">final</span> Arguments args;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> args = <span class="keyword">new</span> Arguments(argv);</div><div class="line"> } <span class="keyword">catch</span> (IllegalArgumentException ex) {</div><div class="line"> Slog.e(TAG, ex.getMessage());</div><div class="line"> <span class="comment">// let the process exit</span></div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// The end of of the RuntimeInit event (see #zygoteInit).</span></div><div class="line"> Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);</div><div class="line"></div><div class="line"> <span class="comment">// Remaining arguments are passed to the start class's static main</span></div><div class="line"> invokeStaticMain(args.startClass, args.startArgs, classLoader);</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="RuntimeInit-invokeStaticMain"><a href="#RuntimeInit-invokeStaticMain" class="headerlink" title="RuntimeInit.invokeStaticMain"></a>RuntimeInit.invokeStaticMain</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">invokeStaticMain</span><span class="params">(String className, String[] argv, ClassLoader classLoader)</span></span></div><div class="line"><span class="function"> <span class="keyword">throws</span> ZygoteInit.MethodAndArgsCaller </span>{</div><div class="line"> Class<?> cl;</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> cl = Class.forName(className, <span class="keyword">true</span>, classLoader);</div><div class="line"> } <span class="keyword">catch</span> (ClassNotFoundException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line"> <span class="string">"Missing class when invoking static main "</span> + className,</div><div class="line"> ex);</div><div class="line"> }</div><div class="line"></div><div class="line"> Method m;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> m = cl.getMethod(<span class="string">"main"</span>, <span class="keyword">new</span> Class[] { String[].class });</div><div class="line"> } <span class="keyword">catch</span> (NoSuchMethodException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line"> <span class="string">"Missing static main on "</span> + className, ex);</div><div class="line"> } <span class="keyword">catch</span> (SecurityException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line"> <span class="string">"Problem getting static main on "</span> + className, ex);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">int</span> modifiers = m.getModifiers();</div><div class="line"> <span class="keyword">if</span> (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(</div><div class="line"> <span class="string">"Main method is not public and static on "</span> + className);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * This throw gets caught in ZygoteInit.main(), which responds</span></div><div class="line"><span class="comment"> * by invoking the exception's run() method. This arrangement</span></div><div class="line"><span class="comment"> * clears up all the stack frames that were required in setting</span></div><div class="line"><span class="comment"> * up the process.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ZygoteInit.MethodAndArgsCaller(m, argv);</div><div class="line">}</div></pre></td></tr></table></figure><p>最终,子进程中,调用invokeStaticMain,抛出ZygoteInit.MethodAndArgsCaller异常,从而跳转到ZygoteInit.main()方法的exception处理中,调用caller.run();</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> mMethod.invoke(<span class="keyword">null</span>, <span class="keyword">new</span> Object[] { mArgs });</div><div class="line"> } <span class="keyword">catch</span> (IllegalAccessException ex) {</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(ex);</div><div class="line"> } <span class="keyword">catch</span> (InvocationTargetException ex) {</div><div class="line"> Throwable cause = ex.getCause();</div><div class="line"> <span class="keyword">if</span> (cause <span class="keyword">instanceof</span> RuntimeException) {</div><div class="line"> <span class="keyword">throw</span> (RuntimeException) cause;</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (cause <span class="keyword">instanceof</span> Error) {</div><div class="line"> <span class="keyword">throw</span> (Error) cause;</div><div class="line"> }</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(ex);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>即,调用ZygoteInit.MethodAndArgsCaller(m, argv)这个main方法,并传参argv</p><p><strong>PS: 为采用抛出异常这种方式来跳转呢?</strong></p><ol><li>java中,线程的方法栈中,包含了一个个的栈帧,每个栈帧都是一个方法</li><li>抛出异常的时候,java会依次将方法栈帧出栈,寻找能够处理异常的栈帧</li><li>因此,zygote fork出来的子进程,最终会将ZygoteInit.main()方法栈帧上面的栈帧都清空掉</li><li>从而是的子进程都是从ZygoteInit.mian()方法起栈的</li></ol><p>而对于父进程,也就是我们的zygote进程, 来看看handleParentProc<br><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">boolean</span> <span class="title">handleParentProc</span><span class="params">(<span class="keyword">int</span> pid,</span></span></div><div class="line"><span class="function"><span class="params"> FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs)</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (pid > <span class="number">0</span>) {</div><div class="line"> setChildPgid(pid);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (descriptors != <span class="keyword">null</span>) {</div><div class="line"> <span class="keyword">for</span> (FileDescriptor fd: descriptors) {</div><div class="line"> IoUtils.closeQuietly(fd);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">boolean</span> usingWrapper = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">if</span> (pipeFd != <span class="keyword">null</span> && pid > <span class="number">0</span>) {</div><div class="line"> DataInputStream is = <span class="keyword">new</span> DataInputStream(<span class="keyword">new</span> FileInputStream(pipeFd));</div><div class="line"> <span class="keyword">int</span> innerPid = -<span class="number">1</span>;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> innerPid = is.readInt();</div><div class="line"> } <span class="keyword">catch</span> (IOException ex) {</div><div class="line"> Log.w(TAG, <span class="string">"Error reading pid from wrapped process, child may have died"</span>, ex);</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> is.close();</div><div class="line"> } <span class="keyword">catch</span> (IOException ex) {</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Ensure that the pid reported by the wrapped process is either the</span></div><div class="line"> <span class="comment">// child process that we forked, or a descendant of it.</span></div><div class="line"> <span class="keyword">if</span> (innerPid > <span class="number">0</span>) {</div><div class="line"> <span class="keyword">int</span> parentPid = innerPid;</div><div class="line"> <span class="keyword">while</span> (parentPid > <span class="number">0</span> && parentPid != pid) {</div><div class="line"> parentPid = Process.getParentPid(parentPid);</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (parentPid > <span class="number">0</span>) {</div><div class="line"> Log.i(TAG, <span class="string">"Wrapped process has pid "</span> + innerPid);</div><div class="line"> pid = innerPid;</div><div class="line"> usingWrapper = <span class="keyword">true</span>;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> Log.w(TAG, <span class="string">"Wrapped process reported a pid that is not a child of "</span></div><div class="line"> + <span class="string">"the process that we forked: childPid="</span> + pid</div><div class="line"> + <span class="string">" innerPid="</span> + innerPid);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> mSocketOutStream.writeInt(pid);</div><div class="line"> mSocketOutStream.writeBoolean(usingWrapper);</div><div class="line"> } <span class="keyword">catch</span> (IOException ex) {</div><div class="line"> Log.e(TAG, <span class="string">"Error writing to command socket"</span>, ex);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">}</div></pre></td></tr></table></figure></p><p>主要做了一些fork清理工作,并没有抛出异常,因此还是在runSelectLoop这个循环中继续往下执行</p><h1 id="完结"><a href="#完结" class="headerlink" title="完结"></a>完结</h1><p>至此,整个zygote进程的启动流程执行完毕,主要做了以下事情:</p><ol><li>app_main.cpp -> main(), AppRuntime的初始化:创建虚拟机、注册jni函数</li><li>执行com.android.internal.os.ZygoteInit -> main()函数</li><li>registerZygoteSocket注册服务端sServerSocket</li><li>preload: 基本资源、库的加载</li><li>如果需要启动systemserver,则启动systemserver进程</li><li>runSelectLoop: 进入无限循环,采用poll + socket的机制,等待client端的请求<br>6.1 请求过来,fork进程,并在新的进程中运行class的main方法<br>6.2 父进程做完清理工作,继续在无限循环中执行</li></ol><p>参考链接:<br><a href="http://blog.csdn.net/yaowei514473839/article/details/53022493" target="_blank" rel="external">http://blog.csdn.net/yaowei514473839/article/details/53022493</a><br><a href="http://blog.csdn.net/yaowei514473839/article/details/53045285" target="_blank" rel="external">http://blog.csdn.net/yaowei514473839/article/details/53045285</a></p>]]></content>
<summary type="html">
<p>从上一篇<a href="http://molingyu.com/2017/09/26/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%B8%80)init%E8%BF%9B%E7%A8%8
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Android" scheme="http://www.molingyu.com/tags/Android/"/>
<category term="源码阅读" scheme="http://www.molingyu.com/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
</entry>
<entry>
<title>Android启动源码阅读(一)init进程的启动</title>
<link href="http://www.molingyu.com/2017/09/26/Android%E5%90%AF%E5%8A%A8%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB(%E4%B8%80)init%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%90%AF%E5%8A%A8/"/>
<id>http://www.molingyu.com/2017/09/26/Android启动源码阅读(一)init进程的启动/</id>
<published>2017-09-25T20:50:02.893Z</published>
<updated>2017-09-25T20:50:02.893Z</updated>
<content type="html"><![CDATA[<p>在Linux系统中,Kernel启动完毕之后,启动的第一个用户空间的进程,就是名为<strong>init</strong>的进程:</p><p>以下是查找init进程源码的过程:</p><ol><li><p>查找init进程mk文件位置:</p><p>查找可执行程序:init的编译MODULE定义,即全局查找字符串: LOCAL_MODULE:= init,从而找到mk文件位置system/core/init/Android.mk</p></li><li><p>从MODULE的LOCAL_SRC_FILES找到init.cpp文件</p></li><li><p>全局查找文件(按两次)init.cpp,从而最终找到init.cpp的源码system/core/init/init.cpp</p></li></ol><h1 id="init启动解析-main函数"><a href="#init启动解析-main函数" class="headerlink" title="init启动解析: main函数"></a>init启动解析: main函数</h1><p>作为init可执行文件的入口init.cpp->main(),我们来看下它是怎么执行的<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">(<span class="keyword">int</span> argc, <span class="keyword">char</span>** argv)</span> </span>{</div><div class="line"> ...</div><div class="line"> <span class="comment">// 将/usr/bin:/bin加入到环境变量中去</span></div><div class="line"> add_environment(<span class="string">"PATH"</span>, _PATH_DEFPATH);</div><div class="line"></div><div class="line"> <span class="keyword">bool</span> is_first_stage = (argc == <span class="number">1</span>) || (<span class="built_in">strcmp</span>(argv[<span class="number">1</span>], <span class="string">"--second-stage"</span>) != <span class="number">0</span>);</div><div class="line"></div><div class="line"> <span class="comment">// Get the basic filesystem setup we need put together in the initramdisk</span></div><div class="line"> <span class="comment">// on / and then we'll let the rc file figure out the rest.</span></div><div class="line"> <span class="keyword">if</span> (is_first_stage) {</div><div class="line"> mount(<span class="string">"tmpfs"</span>, <span class="string">"/dev"</span>, <span class="string">"tmpfs"</span>, MS_NOSUID, <span class="string">"mode=0755"</span>);</div><div class="line"> mkdir(<span class="string">"/dev/pts"</span>, <span class="number">0755</span>);</div><div class="line"> mkdir(<span class="string">"/dev/socket"</span>, <span class="number">0755</span>);</div><div class="line"> mount(<span class="string">"devpts"</span>, <span class="string">"/dev/pts"</span>, <span class="string">"devpts"</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</div><div class="line"> <span class="meta">#<span class="meta-keyword">define</span> MAKE_STR(x) __STRING(x)</span></div><div class="line"> mount(<span class="string">"proc"</span>, <span class="string">"/proc"</span>, <span class="string">"proc"</span>, <span class="number">0</span>, <span class="string">"hidepid=2,gid="</span> MAKE_STR(AID_READPROC));</div><div class="line"> mount(<span class="string">"sysfs"</span>, <span class="string">"/sys"</span>, <span class="string">"sysfs"</span>, <span class="number">0</span>, <span class="literal">NULL</span>);</div><div class="line"> }</div><div class="line"> </div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="comment">// Set up SELinux, including loading the SELinux policy if we're in the kernel domain.</span></div><div class="line"> selinux_initialize(is_first_stage);</div><div class="line"> </div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="comment">// These directories were necessarily created before initial policy load</span></div><div class="line"> <span class="comment">// and therefore need their security context restored to the proper value.</span></div><div class="line"> <span class="comment">// This must happen before /dev is populated by ueventd.</span></div><div class="line"> NOTICE(<span class="string">"Running restorecon...\n"</span>);</div><div class="line"> restorecon(<span class="string">"/dev"</span>);</div><div class="line"> restorecon(<span class="string">"/dev/socket"</span>);</div><div class="line"> restorecon(<span class="string">"/dev/__properties__"</span>);</div><div class="line"> restorecon(<span class="string">"/property_contexts"</span>);</div><div class="line"> restorecon_recursive(<span class="string">"/sys"</span>);</div><div class="line"></div><div class="line"> epoll_fd = epoll_create1(EPOLL_CLOEXEC);</div><div class="line"> </div><div class="line"> ...</div><div class="line"> </div><div class="line"> <span class="comment">//信号处理handler初始化:通过信号量,管理init fork出来的子进程</span></div><div class="line"> signal_handler_init();</div><div class="line"> <span class="comment">//导入默认boot_property</span></div><div class="line"> property_load_boot_defaults();</div><div class="line"> <span class="comment">//导入oem锁状态</span></div><div class="line"> export_oem_lock_status();</div><div class="line"> <span class="comment">//属性服务初始化</span></div><div class="line"> start_property_service();</div><div class="line"> </div><div class="line"> <span class="comment">//创建内建的函数映射key-func的map集合,Action解析触发都依赖与该map查找对应的函数</span></div><div class="line"> <span class="keyword">const</span> BuiltinFunctionMap function_map;</div><div class="line"> Action::set_function_map(&function_map);</div><div class="line"></div><div class="line"> <span class="comment">//init.rc文件的解析</span></div><div class="line"> Parser& parser = Parser::GetInstance();</div><div class="line"> parser.AddSectionParser(<span class="string">"service"</span>,<span class="built_in">std</span>::make_unique<ServiceParser>());</div><div class="line"> parser.AddSectionParser(<span class="string">"on"</span>, <span class="built_in">std</span>::make_unique<ActionParser>());</div><div class="line"> parser.AddSectionParser(<span class="string">"import"</span>, <span class="built_in">std</span>::make_unique<ImportParser>());</div><div class="line"> <span class="comment">//开始解析</span></div><div class="line"> parser.ParseConfig(<span class="string">"/init.rc"</span>);</div><div class="line"></div><div class="line"> ActionManager& am = ActionManager::GetInstance();</div><div class="line"> </div><div class="line"> ...</div><div class="line"></div><div class="line"> <span class="comment">// init进程进入该循环</span></div><div class="line"> <span class="comment">// 1. 执行am的命令</span></div><div class="line"> <span class="comment">// 2. 重启相关的process,这里其实是我们通过service启动的子进程</span></div><div class="line"> <span class="keyword">while</span> (<span class="literal">true</span>) {</div><div class="line"> <span class="keyword">if</span> (!waiting_for_exec) {</div><div class="line"> am.ExecuteOneCommand();</div><div class="line"> restart_processes();</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">int</span> timeout = <span class="number">-1</span>;</div><div class="line"> <span class="keyword">if</span> (process_needs_restart) {</div><div class="line"> timeout = (process_needs_restart - gettime()) * <span class="number">1000</span>;</div><div class="line"> <span class="keyword">if</span> (timeout < <span class="number">0</span>)</div><div class="line"> timeout = <span class="number">0</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (am.HasMoreCommands()) {</div><div class="line"> timeout = <span class="number">0</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> bootchart_sample(&timeout);</div><div class="line"> <span class="comment">//阻塞,等待新的command的到来</span></div><div class="line"> epoll_event ev;</div><div class="line"> <span class="keyword">int</span> nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, <span class="number">1</span>, timeout));</div><div class="line"> <span class="keyword">if</span> (nr == <span class="number">-1</span>) {</div><div class="line"> ERROR(<span class="string">"epoll_wait failed: %s\n"</span>, strerror(errno));</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (nr == <span class="number">1</span>) {</div><div class="line"> ((<span class="keyword">void</span> (*)()) ev.data.ptr)();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">}</div></pre></td></tr></table></figure></p><p>总结下来,init进程做了几件事情:</p><ol><li>bin环境变量的添加</li><li>所需的文件系统的挂载</li><li>信号处理、oem锁、属性服务启动</li><li>init.rc文件的解析</li><li>进入循环,通过ActionManager开始执行Command</li><li>restart_processes,重新启动process,如果有必要的话</li></ol><p>本文,我们只关注两点:</p><ol><li>rc文件的解析</li><li>restart_processes 启动新的process</li></ol><h2 id="init-rc文件的解析过程"><a href="#init-rc文件的解析过程" class="headerlink" title="init.rc文件的解析过程"></a>init.rc文件的解析过程</h2><p>init.rc文件位于system/core/rootdir/init.rc</p><h3 id="rc文件的变化"><a href="#rc文件的变化" class="headerlink" title="rc文件的变化"></a>rc文件的变化</h3><p>在 7.+ 版本的系统中,rc文件的内容根据具体的模块拆分成不同的rc文件,</p><p>比如init.rc文件的头部:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">import /init.environ.rc</div><div class="line">import /init.usb.rc</div><div class="line">import /init.${ro.hardware}.rc</div><div class="line">import /init.usb.configfs.rc</div><div class="line">import /init.${ro.zygote}.rc</div></pre></td></tr></table></figure></p><p>又比如servicemanager的初始化: frameworks/native/cmds/servicemanager/servicemanager.rc</p><p>参考链接:<a href="http://blog.csdn.net/sunao2002002/article/details/52454878" target="_blank" rel="external">http://blog.csdn.net/sunao2002002/article/details/52454878</a></p><h3 id="解析源码段分析"><a href="#解析源码段分析" class="headerlink" title="解析源码段分析"></a>解析源码段分析</h3><p>先来看看代码段<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line">Parser& parser = Parser::GetInstance();</div><div class="line">parser.AddSectionParser(<span class="string">"service"</span>,<span class="built_in">std</span>::make_unique<ServiceParser>());</div><div class="line">parser.AddSectionParser(<span class="string">"on"</span>, <span class="built_in">std</span>::make_unique<ActionParser>());</div><div class="line">parser.AddSectionParser(<span class="string">"import"</span>, <span class="built_in">std</span>::make_unique<ImportParser>());</div><div class="line">parser.ParseConfig(<span class="string">"/init.rc"</span>);</div></pre></td></tr></table></figure></p><ol><li><p>Parser是一个单例,全局字符串查找 Parser::GetInstance,即可找到定义位置system/core/init/init_parser.cpp</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">Parser& Parser::GetInstance() {</div><div class="line"> <span class="keyword">static</span> Parser instance;</div><div class="line"> <span class="keyword">return</span> instance;</div><div class="line">}</div></pre></td></tr></table></figure></li><li><p>调用AddSectionParser将几个解析器放置到map中:</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> Parser::AddSectionParser(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& name,</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">unique_ptr</span><SectionParser> parser) {</div><div class="line"> section_parsers_[name] = <span class="built_in">std</span>::move(parser);</div><div class="line">}</div></pre></td></tr></table></figure></li><li><p>开始解析:<code>parser.ParseConfig("/init.rc");</code></p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> Parser::ParseConfig(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& path) {</div><div class="line"> <span class="keyword">if</span> (is_dir(path.c_str())) {</div><div class="line"> <span class="keyword">return</span> ParseConfigDir(path);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> ParseConfigFile(path);</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><p>由于传入的”/init.rc”是一个文件,因此开始<code>ParseConfigFile(path)</code>解析</p><ol><li>file解析<figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> Parser::ParseConfigFile(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& path) {</div><div class="line"> INFO(<span class="string">"Parsing file %s...\n"</span>, path.c_str());</div><div class="line"> Timer t;</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> data;</div><div class="line"> <span class="comment">//将file内容读入data字符串中</span></div><div class="line"> <span class="keyword">if</span> (!read_file(path.c_str(), &data)) {</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//内容字符串修正</span></div><div class="line"> data.push_back(<span class="string">'\n'</span>); <span class="comment">// <span class="doctag">TODO:</span> fix parse_config.</span></div><div class="line"> <span class="comment">//4.1 解析文件内容</span></div><div class="line"> ParseData(path, data);</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>& sp : section_parsers_) {</div><div class="line"> <span class="comment">//4.2 解析文件完毕</span></div><div class="line"> sp.second->EndFile(path);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Turning this on and letting the INFO logging be discarded adds 0.2s to</span></div><div class="line"> <span class="comment">// Nexus 9 boot time, so it's disabled by default.</span></div><div class="line"> <span class="keyword">if</span> (<span class="literal">false</span>) DumpState();</div><div class="line"></div><div class="line"> NOTICE(<span class="string">"(Parsing %s took %.2fs.)\n"</span>, path.c_str(), t.duration());</div><div class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><h3 id="ParseData-解析说明"><a href="#ParseData-解析说明" class="headerlink" title="ParseData()解析说明"></a>ParseData()解析说明</h3><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> Parser::ParseData(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& filename, <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& data) {</div><div class="line"> <span class="comment">//<span class="doctag">TODO:</span> Use a parser with const input and remove this copy</span></div><div class="line"> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="keyword">char</span>> data_copy(data.begin(), data.end());</div><div class="line"> data_copy.push_back(<span class="string">'\0'</span>);</div><div class="line"> <span class="comment">//初始化解析参数</span></div><div class="line"> parse_state state;</div><div class="line"> state.filename = filename.c_str();</div><div class="line"> state.line = <span class="number">0</span>;</div><div class="line"> state.ptr = &data_copy[<span class="number">0</span>];</div><div class="line"> state.nexttoken = <span class="number">0</span>;</div><div class="line"> <span class="comment">//解析器</span></div><div class="line"> SectionParser* section_parser = <span class="literal">nullptr</span>;</div><div class="line"> <span class="comment">//解析出来的参数存放位置</span></div><div class="line"> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>> args;</div><div class="line"></div><div class="line"> <span class="keyword">for</span> (;;) {</div><div class="line"> <span class="comment">//next_token():真正解析文件的地方</span></div><div class="line"> <span class="keyword">switch</span> (next_token(&state)) {</div><div class="line"> <span class="keyword">case</span> T_EOF:</div><div class="line"> <span class="comment">//解析到文件末尾</span></div><div class="line"> <span class="keyword">if</span> (section_parser) {</div><div class="line"> section_parser->EndSection();</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> <span class="keyword">case</span> T_NEWLINE:</div><div class="line"> <span class="comment">//新行</span></div><div class="line"> state.line++;</div><div class="line"> <span class="keyword">if</span> (args.empty()) {</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (section_parsers_.count(args[<span class="number">0</span>])) {</div><div class="line"> <span class="comment">//新的一行开始,如果此前的section_parser不为空,则结束那一行的解析:EndSection</span></div><div class="line"> <span class="keyword">if</span> (section_parser) {</div><div class="line"> section_parser->EndSection();</div><div class="line"> }</div><div class="line"> section_parser = section_parsers_[args[<span class="number">0</span>]].get();</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> ret_err;</div><div class="line"> <span class="keyword">if</span> (!section_parser->ParseSection(args, &ret_err)) {</div><div class="line"> parse_error(&state, <span class="string">"%s\n"</span>, ret_err.c_str());</div><div class="line"> section_parser = <span class="literal">nullptr</span>;</div><div class="line"> }</div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (section_parser) {</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> ret_err;</div><div class="line"> <span class="keyword">if</span> (!section_parser->ParseLineSection(args, state.filename,</div><div class="line"> state.line, &ret_err)) {</div><div class="line"> parse_error(&state, <span class="string">"%s\n"</span>, ret_err.c_str());</div><div class="line"> }</div><div class="line"> }</div><div class="line"> args.clear();</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> <span class="keyword">case</span> T_TEXT:</div><div class="line"> <span class="comment">//解析到字符串内容:例如 service zygote /system/bin/app_process</span></div><div class="line"> <span class="comment">//则解析到的结果是args={"service", "zygote", "/system/bin/app_process"}</span></div><div class="line"> args.emplace_back(state.text);</div><div class="line"> <span class="keyword">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>GetInstance</p><h3 id="举例说明解析过程"><a href="#举例说明解析过程" class="headerlink" title="举例说明解析过程"></a>举例说明解析过程</h3><ol><li>读取init.rc文件时,遇到import语句,因此args[0] = “import”,采用ImportParser进行解析</li><li><p>调用ImportParser->ParseSection进行解析:args={“import”, “/init.${ro.zygote}.rc”}</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> ImportParser::ParseSection(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>>& args,</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span>* err) {</div><div class="line"> <span class="keyword">if</span> (args.size() != <span class="number">2</span>) {</div><div class="line"> *err = <span class="string">"single argument needed for import\n"</span>;</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> conf_file;</div><div class="line"> <span class="comment">//通过expand_props将${ro.zygote}替换成对应平台的实现,例如zygote32,因此文件名为:init.zygote32.rc</span></div><div class="line"> <span class="keyword">bool</span> ret = expand_props(args[<span class="number">1</span>], &conf_file);</div><div class="line"> <span class="keyword">if</span> (!ret) {</div><div class="line"> *err = <span class="string">"error while expanding import"</span>;</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> INFO(<span class="string">"Added '%s' to import list\n"</span>, conf_file.c_str());</div><div class="line"> <span class="comment">//将解析出来,import的真正文件名放到imports_列表中</span></div><div class="line"> imports_.emplace_back(<span class="built_in">std</span>::move(conf_file));</div><div class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</div><div class="line">}</div></pre></td></tr></table></figure></li><li><p>回到Parser::ParseConfigFile,当文件解析完毕之后,调用所有的Parser->EndFile</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>& sp : section_parsers_) {</div><div class="line"> <span class="comment">//4.2 解析文件完毕</span></div><div class="line"> sp.second->EndFile(path);</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><p>因此,我们看下ImportParser->EndFile():<br><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> ImportParser::EndFile(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& filename) {</div><div class="line"> <span class="keyword">auto</span> current_imports = <span class="built_in">std</span>::move(imports_);</div><div class="line"> imports_.clear();</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>& s : current_imports) {</div><div class="line"> <span class="keyword">if</span> (!Parser::GetInstance().ParseConfig(s)) {</div><div class="line"> ERROR(<span class="string">"could not import file '%s' from '%s': %s\n"</span>,</div><div class="line"> s.c_str(), filename.c_str(), strerror(errno));</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></p><p>由此可见,又针对每个文件,进行了Parser::GetInstance().ParseConfig(s)解析</p><ol><li><p>imprt进来的file的解析步骤仍然走的:</p><ul><li>Parser::ParseConfig</li><li>Parser::ParseConfigFile</li><li>循环1. Parser::ParseData</li><li>循环2. system/core/init/parser.cpp->next_token()</li><li>循环3. Parser::ParseSection</li><li>循环4. Parser::EndSection</li></ul></li><li><p>我们来看service的解析:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server</div><div class="line"> class main</div><div class="line"> socket zygote stream 660 root system</div><div class="line"> onrestart write /sys/android_power/request_state wake</div><div class="line"> onrestart write /sys/power/state on</div><div class="line"> onrestart restart audioserver</div><div class="line"> onrestart restart cameraserver</div><div class="line"> onrestart restart media</div><div class="line"> onrestart restart netd</div><div class="line"> writepid /dev/cpuset/foreground/tasks</div></pre></td></tr></table></figure><ol><li>在ParserData()的时候,args[0]=”service”,采用ServiceParser进行解析<figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> ServiceParser::ParseSection(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>>& args,</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span>* err) {</div><div class="line"> <span class="keyword">if</span> (args.size() < <span class="number">3</span>) {</div><div class="line"> *err = <span class="string">"services must have a name and a program"</span>;</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& name = args[<span class="number">1</span>];</div><div class="line"> <span class="keyword">if</span> (!IsValidName(name)) {</div><div class="line"> *err = StringPrintf(<span class="string">"invalid service name '%s'"</span>, name.c_str());</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>> str_args(args.begin() + <span class="number">2</span>, args.end());</div><div class="line"> service_ = <span class="built_in">std</span>::make_unique<Service>(name, <span class="string">"default"</span>, str_args);</div><div class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><p>由此可见,service关键字的解析,将会创建Service对象,并赋值给ServiceParser的service_成员</p><ol><li>当这一行解析完毕之后,进入下一行,由于下一行的args[0]不为{“service”,”on”,”import”}中的任意一个,因此进入解析方法ParseLineSection <figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> ServiceParser::ParseLineSection(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>>& args, <span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& filename, <span class="keyword">int</span> line, <span class="built_in">std</span>::<span class="built_in">string</span>* err) <span class="keyword">const</span> {</div><div class="line"> <span class="keyword">return</span> service_ ? service_->HandleLine(args, err) : <span class="literal">false</span>;</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><p>HandleLine方法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">bool</span> Service::HandleLine(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">vector</span><<span class="built_in">std</span>::<span class="built_in">string</span>>& args, <span class="built_in">std</span>::<span class="built_in">string</span>* err) {</div><div class="line"> <span class="keyword">if</span> (args.empty()) {</div><div class="line"> *err = <span class="string">"option needed, but not provided"</span>;</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//根据OptionHandlerMap,找寻args[0]所对应的函数</span></div><div class="line"> <span class="keyword">static</span> <span class="keyword">const</span> OptionHandlerMap handler_map;</div><div class="line"> <span class="keyword">auto</span> handler = handler_map.FindFunction(args[<span class="number">0</span>], args.size() - <span class="number">1</span>, err);</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (!handler) {</div><div class="line"> <span class="keyword">return</span> <span class="literal">false</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//找到args[0]对应的方法,调用该方法,并将方法的返回值true/false,</span></div><div class="line"> <span class="comment">//返回: 这些方法基本上都是service_的属性设置,返回的都是boolean值</span></div><div class="line"> <span class="keyword">return</span> (<span class="keyword">this</span>->*handler)(args, err);</div><div class="line">}</div></pre></td></tr></table></figure><p>//OptionHandlerMap定义如下</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">Service::OptionHandlerMap::Map& Service::OptionHandlerMap::<span class="built_in">map</span>() <span class="keyword">const</span> {</div><div class="line"> <span class="keyword">constexpr</span> <span class="built_in">std</span>::<span class="keyword">size_t</span> kMax = <span class="built_in">std</span>::numeric_limits<<span class="built_in">std</span>::<span class="keyword">size_t</span>>::max();</div><div class="line"> <span class="keyword">static</span> <span class="keyword">const</span> Map option_handlers = {</div><div class="line"> {<span class="string">"class"</span>, {<span class="number">1</span>, <span class="number">1</span>, &Service::HandleClass}},</div><div class="line"> {<span class="string">"console"</span>, {<span class="number">0</span>, <span class="number">0</span>, &Service::HandleConsole}},</div><div class="line"> {<span class="string">"critical"</span>, {<span class="number">0</span>, <span class="number">0</span>, &Service::HandleCritical}},</div><div class="line"> {<span class="string">"disabled"</span>, {<span class="number">0</span>, <span class="number">0</span>, &Service::HandleDisabled}},</div><div class="line"> {<span class="string">"group"</span>, {<span class="number">1</span>, NR_SVC_SUPP_GIDS + <span class="number">1</span>, &Service::HandleGroup}},</div><div class="line"> {<span class="string">"ioprio"</span>, {<span class="number">2</span>, <span class="number">2</span>, &Service::HandleIoprio}},</div><div class="line"> {<span class="string">"keycodes"</span>, {<span class="number">1</span>, kMax, &Service::HandleKeycodes}},</div><div class="line"> {<span class="string">"oneshot"</span>, {<span class="number">0</span>, <span class="number">0</span>, &Service::HandleOneshot}},</div><div class="line"> {<span class="string">"onrestart"</span>, {<span class="number">1</span>, kMax, &Service::HandleOnrestart}},</div><div class="line"> {<span class="string">"seclabel"</span>, {<span class="number">1</span>, <span class="number">1</span>, &Service::HandleSeclabel}},</div><div class="line"> {<span class="string">"setenv"</span>, {<span class="number">2</span>, <span class="number">2</span>, &Service::HandleSetenv}},</div><div class="line"> {<span class="string">"socket"</span>, {<span class="number">3</span>, <span class="number">6</span>, &Service::HandleSocket}},</div><div class="line"> {<span class="string">"user"</span>, {<span class="number">1</span>, <span class="number">1</span>, &Service::HandleUser}},</div><div class="line"> {<span class="string">"writepid"</span>, {<span class="number">1</span>, kMax, &Service::HandleWritepid}},</div><div class="line"> };</div><div class="line"> <span class="keyword">return</span> option_handlers;</div><div class="line">}</div></pre></td></tr></table></figure><ol><li>当所有的Line解析完毕,到达文件末尾,则调用ServiceParser::EndSection方法:<figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> ServiceParser::EndSection() {</div><div class="line"> <span class="keyword">if</span> (service_) {</div><div class="line"> ServiceManager::GetInstance().AddService(<span class="built_in">std</span>::move(service_));</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure></li></ol><p>将刚才解析的service_成员,move到ServiceManager的列表中</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> ServiceManager::AddService(<span class="built_in">std</span>::<span class="built_in">unique_ptr</span><Service> service) {</div><div class="line"> Service* old_service = FindServiceByName(service->name());</div><div class="line"> <span class="keyword">if</span> (old_service) {</div><div class="line"> ERROR(<span class="string">"ignored duplicate definition of service '%s'"</span>,</div><div class="line"> service->name().c_str());</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"> services_.emplace_back(<span class="built_in">std</span>::move(service));</div><div class="line">}</div></pre></td></tr></table></figure><ol><li>至此,init.zygote32.rc文件解析完毕</li></ol></li></ol><h3 id="restart-processes"><a href="#restart-processes" class="headerlink" title="restart_processes"></a>restart_processes</h3><p>前面分析init.cpp->main()函数的时候,在while循环中,调用了restart_processes方法</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">void</span> <span class="title">restart_processes</span><span class="params">()</span></span></div><div class="line"><span class="function"></span>{</div><div class="line"> process_needs_restart = <span class="number">0</span>;</div><div class="line"> ServiceManager::GetInstance().</div><div class="line"> ForEachServiceWithFlags(SVC_RESTARTING, [] (Service* s) {</div><div class="line"> s->RestartIfNeeded(process_needs_restart);</div><div class="line"> });</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">void</span> ServiceManager::ForEachServiceWithFlags(<span class="keyword">unsigned</span> matchflags,</div><div class="line"> <span class="keyword">void</span> (*func)(Service* svc)) <span class="keyword">const</span> {</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>& s : services_) {</div><div class="line"> <span class="keyword">if</span> (s->flags() & matchflags) {</div><div class="line"> func(s.get());</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><p>从代码看到,这段代码对每一个Service,都进行了调用函数调用<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">:s->RestartIfNeeded(process_needs_restart);</div></pre></td></tr></table></figure></p><p>因此,最终调用到了</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">void</span> Service::RestartIfNeeded(<span class="keyword">time_t</span>& process_needs_restart) {</div><div class="line"> <span class="keyword">time_t</span> next_start_time = time_started_ + <span class="number">5</span>;</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (next_start_time <= gettime()) {</div><div class="line"> flags_ &= (~SVC_RESTARTING);</div><div class="line"> Start();</div><div class="line"> <span class="keyword">return</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">if</span> ((next_start_time < process_needs_restart) ||</div><div class="line"> (process_needs_restart == <span class="number">0</span>)) {</div><div class="line"> process_needs_restart = next_start_time;</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="调用到了Service-Start-方法-system-core-init-service-cpp"><a href="#调用到了Service-Start-方法-system-core-init-service-cpp" class="headerlink" title="调用到了Service:Start()方法: system/core/init/service.cpp"></a>调用到了Service:Start()方法: system/core/init/service.cpp</h3><p>这段代码比较长,就不贴了,列举几个重要的片段:</p><ul><li><p>fork一个新的进程</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">pid_t</span> pid = fork();</div></pre></td></tr></table></figure></li><li><p>在新的进程中,如果sockets_不为空,就创建socket: 此处init.zygote32.rc文件中,socket zygote stream 660 root system</p></li></ul><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span> (<span class="keyword">const</span> <span class="keyword">auto</span>& si : sockets_) {</div><div class="line"> <span class="keyword">int</span> socket_type = ((si.type == <span class="string">"stream"</span> ? SOCK_STREAM :</div><div class="line"> (si.type == <span class="string">"dgram"</span> ? SOCK_DGRAM :</div><div class="line"> SOCK_SEQPACKET)));</div><div class="line"> <span class="keyword">const</span> <span class="keyword">char</span>* socketcon =</div><div class="line"> !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();</div><div class="line"></div><div class="line"> <span class="keyword">int</span> s = create_socket(si.name.c_str(), socket_type, si.perm,</div><div class="line"> si.uid, si.gid, socketcon);</div><div class="line"> <span class="keyword">if</span> (s >= <span class="number">0</span>) {</div><div class="line"> <span class="comment">//调用PublishSocket,将si.name=zygote,设置到环境变量"ANDROID_SOCKET_ENV_PREFIX si.name"中去</span></div><div class="line"> PublishSocket(si.name, s);</div><div class="line"> }</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//最终通过execve来执行 /system/bin/app_process</span></div><div class="line"><span class="keyword">if</span> (execve(strs[<span class="number">0</span>], (<span class="keyword">char</span>**) &strs[<span class="number">0</span>], (<span class="keyword">char</span>**) ENV) < <span class="number">0</span>) {</div><div class="line"> ERROR(<span class="string">"cannot execve('%s'): %s\n"</span>, strs[<span class="number">0</span>], strerror(errno));</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keyword">void</span> Service::PublishSocket(<span class="keyword">const</span> <span class="built_in">std</span>::<span class="built_in">string</span>& name, <span class="keyword">int</span> fd) <span class="keyword">const</span> {</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> key = StringPrintf(ANDROID_SOCKET_ENV_PREFIX <span class="string">"%s"</span>, name.c_str());</div><div class="line"> <span class="built_in">std</span>::<span class="built_in">string</span> val = StringPrintf(<span class="string">"%d"</span>, fd);</div><div class="line"> add_environment(key.c_str(), val.c_str());</div><div class="line"></div><div class="line"> <span class="comment">/* make sure we don't close-on-exec */</span></div><div class="line"> fcntl(fd, F_SETFD, <span class="number">0</span>);</div><div class="line">}</div></pre></td></tr></table></figure><p>因此会创建一个名为zygote的socket,挂在在/dev/socket/zygote节点下,</p><p>最终通过execve来执行 /system/bin/app_process</p><p>至此,一个service进程就解析,并创建进程,在新进程中开始执行</p><h2 id="完结"><a href="#完结" class="headerlink" title="完结"></a>完结</h2><p>上述分析,仅仅针对service关键字做了分析,其他的关键字on、class等等,同理分析</p><p>参考资料:</p><ul><li><a href="http://gityuan.com/2016/02/05/android-init/" target="_blank" rel="external">http://gityuan.com/2016/02/05/android-init/</a></li><li><a href="http://blog.csdn.net/A8316124/article/details/62224237" target="_blank" rel="external">http://blog.csdn.net/A8316124/article/details/62224237</a></li><li><a href="http://blog.csdn.net/sunao2002002/article/details/52454878" target="_blank" rel="external">http://blog.csdn.net/sunao2002002/article/details/52454878</a></li><li>system/core/init/readme.txt</li></ul>]]></content>
<summary type="html">
<p>在Linux系统中,Kernel启动完毕之后,启动的第一个用户空间的进程,就是名为<strong>init</strong>的进程:</p>
<p>以下是查找init进程源码的过程:</p>
<ol>
<li><p>查找init进程mk文件位置:</p>
<p>查找可执行程
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Android" scheme="http://www.molingyu.com/tags/Android/"/>
<category term="源码阅读" scheme="http://www.molingyu.com/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
</entry>
<entry>
<title>Android源码阅读准备</title>
<link href="http://www.molingyu.com/2017/09/25/Android%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB%E6%8A%80%E5%B7%A7/"/>
<id>http://www.molingyu.com/2017/09/25/Android源码阅读技巧/</id>
<published>2017-09-25T14:34:15.387Z</published>
<updated>2017-09-25T14:34:15.387Z</updated>
<content type="html"><![CDATA[<h2 id="源码下载"><a href="#源码下载" class="headerlink" title="源码下载"></a>源码下载</h2><p>参考<a href="https://source.android.com/source/downloading" target="_blank" rel="external">官方doc</a>,需要自备梯子</p><h2 id="选定分支"><a href="#选定分支" class="headerlink" title="选定分支"></a>选定分支</h2><p>我自己的是Nexus6,写这篇日志时,当前官网适配的最新版本是 7.1.1_r45,因此我的源码编译和阅读都是基于这个分支,手机上也是运行的这个版本。</p><h2 id="工欲善其事,必先利其器"><a href="#工欲善其事,必先利其器" class="headerlink" title="工欲善其事,必先利其器"></a>工欲善其事,必先利其器</h2><ul><li><strong>Windows</strong> : Source Insight,跟踪代码的一大利器</li><li><strong>Linux</strong> : wine + Source Insight,各种问题,够折腾</li><li><strong>Linux</strong> : AndroidStudio,各种java索引跳转溜溜的,除了native代码</li></ul><p>因此,我采用了<a href="http://blog.csdn.net/yanbober/article/details/48846331" target="_blank" rel="external"><strong>AndroidStudio导入Android源码</strong></a>的方式来浏览源码</p><p>这样唯一一个问题就是native代码的阅读,需要自己手动全局查找:</p><blockquote><p>1.查找某个类:Ctrl + Shift + F,然后输入类名称,比如查找native的Looper类,可以通过全局搜索” Looper {“,来定位到类定义位置。</p><p>2.查找某个方法: Ctrl + Shift + F, </p><ul><li>方法名</li><li>方法名 + {</li><li>正则表达式:” “ + 方法名 + [(] (.*) [)] + [\n] + [{]</li><li>某个类中的某个方法,直接搜: “ “ + 方法名 + “(“</li><li>有些方法是类定义的C++方法,可以采用: “::” + 方法名, 的方式来搜索</li></ul><p>3.查找某个文件: Ctrl + Shift + N(或者按两次), 输入文件名,如果有多个匹配,需要谨慎选择,通常情况下都是优先匹配到的第一个文件。</p></blockquote><h2 id="完"><a href="#完" class="headerlink" title="完"></a>完</h2><p>如此,我们就可以遨游在AndroidSource的海洋里了</p><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://source.android.com/source/downloading" target="_blank" rel="external">https://source.android.com/source/downloading</a><br><a href="http://blog.csdn.net/yanbober/article/details/48846331" target="_blank" rel="external">http://blog.csdn.net/yanbober/article/details/48846331</a><br><a href="http://www.runoob.com/regexp/regexp-syntax.html" target="_blank" rel="external">http://www.runoob.com/regexp/regexp-syntax.html</a></p>]]></content>
<summary type="html">
<h2 id="源码下载"><a href="#源码下载" class="headerlink" title="源码下载"></a>源码下载</h2><p>参考<a href="https://source.android.com/source/downloading" targ
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Android" scheme="http://www.molingyu.com/tags/Android/"/>
<category term="源码阅读" scheme="http://www.molingyu.com/tags/%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/"/>
</entry>
<entry>
<title>一个epoll实例</title>
<link href="http://www.molingyu.com/2017/09/18/%E4%B8%80%E4%B8%AAepoll%E5%AE%9E%E4%BE%8B/"/>
<id>http://www.molingyu.com/2017/09/18/一个epoll实例/</id>
<published>2017-09-18T06:07:49.490Z</published>
<updated>2017-09-18T06:07:49.490Z</updated>
<content type="html"><![CDATA[<p>epoll 于Linux 2.5.44引入,旨在替换select和poll系统函数。</p><p>相对于select和poll来说,epoll更加灵活高效:</p><ul><li>没有监视描述符数量单进程1024限制</li><li>epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。</li></ul><h2 id="epoll在Android中的应用"><a href="#epoll在Android中的应用" class="headerlink" title="epoll在Android中的应用"></a>epoll在Android中的应用</h2><p>epoll机制在Android系统中扮演着一个很重要的角色,</p><ol><li>在MessageQueue的队列中,当队列为空时需要阻塞Looper线程,队列非空时候需要唤醒线程,使用到了epoll + eventfd(比pipe更高效的事件驱动,在<a href="https://android.googlesource.com/platform/system/core/+/8892ce6%5E!/" target="_blank" rel="external">6.0引入</a>)机制,高效的管理着消息队列</li><li>java NIO中 Selector采用了epoll机制实现SocketChannel管道事件轮询</li></ol><h2 id="实例代码(采用epoll-pipe实现)"><a href="#实例代码(采用epoll-pipe实现)" class="headerlink" title="实例代码(采用epoll + pipe实现)"></a>实例代码(采用epoll + pipe实现)</h2><p>本例我们采用 epoll + pipe的机制,简单的模拟一个通信唤醒的场景来理解epoll通信,更深入的理解,可以阅读libevent源码</p><ol><li>创建管道</li><li>创建epll事件:并设置关注的事件类型</li><li>创建epoll</li><li>往epoll注册事件</li><li>fork一个子进程,sleep(3)秒后,往管道写入数据</li><li>父进程挂起,监听事件源(管道读取端fd)事件</li></ol><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div></pre></td><td class="code"><pre><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><errno.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/epoll.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdio></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdlib></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstring></span></span></div><div class="line"></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</div><div class="line"> <span class="comment">//最大事件数</span></div><div class="line"> <span class="keyword">const</span> <span class="keyword">int</span> MAXEVENTS = <span class="number">1024</span>;</div><div class="line"></div><div class="line"> <span class="keyword">int</span> ret;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 1. 创建管道,并将管道两端的fd存放在数组pipe_fd中</span></div><div class="line"><span class="comment"> * pipe_fd[0] : 管道输出端,可读取fd</span></div><div class="line"><span class="comment"> * pipe_fd[1] : 管道输入端,可写入fd</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> pipe_fd[<span class="number">2</span>];</div><div class="line"> <span class="keyword">if</span> ((ret = pipe(pipe_fd)) < <span class="number">0</span>) {</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"create pipe fail:"</span> << ret << <span class="string">",errno:"</span> << errno << <span class="built_in">endl</span>;</div><div class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 2. 创建epoll关注事件源的事件类型</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> <span class="title">ev</span>;</span></div><div class="line"> <span class="comment">//设置监听事件源</span></div><div class="line"> ev.data.fd = pipe_fd[<span class="number">0</span>];</div><div class="line"> <span class="comment">//设置监听什么事件:EPOLLIN, 事件源可读事件, EPOLLET 边缘触发模式(Edge Triggered)</span></div><div class="line"> ev.events = EPOLLIN | EPOLLET;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 3. 创建epoll对象,返回epoll对象的fd地址</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> epfd = epoll_create(MAXEVENTS);</div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 4. 往epoll对象中 添加/修改/删除 一个事件(事件源fd, 事件类型&ev)</span></div><div class="line"><span class="comment"> * EPOLL_CTL_ADD:注册新的fd到epfd中;</span></div><div class="line"><span class="comment"> * EPOLL_CTL_MOD:修改已经注册的fd的监听事件;</span></div><div class="line"><span class="comment"> * EPOLL_CTL_DEL:从epfd中删除一个fd;</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> ret = epoll_ctl(epfd, EPOLL_CTL_ADD, pipe_fd[<span class="number">0</span>], &ev);</div><div class="line"> <span class="comment">//校验</span></div><div class="line"> <span class="keyword">if</span> (ret != <span class="number">0</span>) {</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"epoll_ctl fail:"</span> << ret << <span class="string">",errno:"</span> << errno << <span class="built_in">endl</span>;</div><div class="line"> close(pipe_fd[<span class="number">0</span>]);</div><div class="line"> close(pipe_fd[<span class="number">1</span>]);</div><div class="line"> close(epfd);</div><div class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//fork一个进程,来读取epoll事件</span></div><div class="line"> <span class="keyword">int</span> pid = fork();</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (pid > <span class="number">0</span>) {<span class="comment">//父进程</span></div><div class="line"> <span class="comment">//监听事件数组</span></div><div class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> <span class="title">events</span>[<span class="title">MAXEVENTS</span>];</span></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 6. 使用epoll,开始监听事件,并将事件放置到数组events中</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * epoll_wait会阻塞当前线程,当监听的事件发生的时候,会唤醒该线程</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> count = epoll_wait(epfd, events, MAXEVENTS, <span class="number">5000</span>);</div><div class="line"> <span class="keyword">char</span> r_buf[<span class="number">100</span>];</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < count; i++) {</div><div class="line"> <span class="comment">//校验</span></div><div class="line"> <span class="keyword">if</span> ((events[i].data.fd == pipe_fd[<span class="number">0</span>]) && (events[<span class="number">0</span>].events & EPOLLIN)) {</div><div class="line"> <span class="keyword">int</span> r_num = read(pipe_fd[<span class="number">0</span>], r_buf, <span class="number">100</span>);</div><div class="line"> <span class="built_in">printf</span>(<span class="string">"parrent read num is %d bytes data from the pipe, value is %d \n"</span>, r_num, atoi(r_buf));</div><div class="line"> }</div><div class="line"> }</div><div class="line"> close(pipe_fd[<span class="number">1</span>]);</div><div class="line"> close(pipe_fd[<span class="number">0</span>]);</div><div class="line"> close(epfd);</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"parent close read fd[0], wirte fd[1] and epfd over"</span> << <span class="built_in">endl</span>;</div><div class="line"></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pid == <span class="number">0</span>) {<span class="comment">//子进程</span></div><div class="line"> <span class="comment">//子进程不进行读取操作,关闭读取fd</span></div><div class="line"> close(pipe_fd[<span class="number">0</span>]);<span class="comment">//read</span></div><div class="line"> <span class="built_in">cout</span> << <span class="string">"sub does't read, so close read fd[0], over"</span> << <span class="built_in">endl</span>;</div><div class="line"></div><div class="line"> <span class="comment">//当前线程睡眠3秒</span></div><div class="line"> sleep(<span class="number">3</span>);</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 5. 子进程开始向管道写入数据,触发EPOLLIN事件</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">char</span> w_buf[<span class="number">100</span>];</div><div class="line"> <span class="built_in">strcpy</span>(w_buf, <span class="string">"1234"</span>);</div><div class="line"> <span class="keyword">if</span> (write(pipe_fd[<span class="number">1</span>], w_buf, <span class="number">5</span>) != <span class="number">-1</span>)<span class="comment">//you can remove this line for learn</span></div><div class="line"> <span class="built_in">printf</span>(<span class="string">"sub write write num 1234, over \n"</span>);</div><div class="line"> <span class="comment">//关闭写入端管道fd</span></div><div class="line"> close(pipe_fd[<span class="number">1</span>]);<span class="comment">//write</span></div><div class="line"> <span class="built_in">printf</span>(<span class="string">"sub close write fd[1] over \n"</span>);</div><div class="line"></div><div class="line"> } <span class="keyword">else</span> { <span class="comment">//pid<0, fork error</span></div><div class="line"> close(pipe_fd[<span class="number">0</span>]);</div><div class="line"> close(pipe_fd[<span class="number">1</span>]);</div><div class="line"> close(epfd);</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"fork error:"</span> << pid << <span class="string">", close fds over"</span> << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="改用epoll-eventfd来实现"><a href="#改用epoll-eventfd来实现" class="headerlink" title="改用epoll + eventfd来实现"></a>改用epoll + eventfd来实现</h2><p>eventfd在2.6.22引入,是比pipe更高效的线程间事件通知机制,它的缓冲区只有8个字节。</p><p>eventfd 只能用于线程间、父子进程间的通信</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//</span></div><div class="line"><span class="comment">// Created by milo on 17-9-18.</span></div><div class="line"><span class="comment">//</span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><iostream></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><unistd.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><errno.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/epoll.h></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdio></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstdlib></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><cstring></span></span></div><div class="line"><span class="meta">#<span class="meta-keyword">include</span> <span class="meta-string"><sys/eventfd.h></span></span></div><div class="line"></div><div class="line"><span class="keyword">using</span> <span class="keyword">namespace</span> <span class="built_in">std</span>;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">int</span> <span class="title">main</span><span class="params">()</span> </span>{</div><div class="line"></div><div class="line"> <span class="keyword">const</span> <span class="keyword">int</span> MAXEVENTS = <span class="number">1024</span>;</div><div class="line"></div><div class="line"> <span class="keyword">int</span> ret;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * eventfd (unsigned int __count, int __flags)</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * man: http://man7.org/linux/man-pages/man2/eventfd.2.html</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * initval: eventfd设备初始值</span></div><div class="line"><span class="comment"> * flags: 在2.6.26之前的版本,必须设置为0,之后的版本有以下值:</span></div><div class="line"><span class="comment"> * EFD_SEMAPHORE</span></div><div class="line"><span class="comment"> * EFD_CLOEXEC</span></div><div class="line"><span class="comment"> * EFD_NONBLOCK</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> efd = eventfd(<span class="number">0</span>, <span class="number">0</span>);</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 1. 创建epoll关注事件源的事件类型</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> <span class="title">ev</span>;</span></div><div class="line"> <span class="comment">//设置监听事件源</span></div><div class="line"> ev.data.fd = efd;</div><div class="line"> <span class="comment">//设置监听什么事件:EPOLLIN, 事件源可读事件, EPOLLET 边缘触发模式(Edge Triggered)</span></div><div class="line"> ev.events = EPOLLIN | EPOLLET;</div><div class="line"></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 2. 创建epoll对象,返回epoll对象的fd地址</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> epfd = epoll_create(MAXEVENTS);</div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 3. 往epoll对象中 添加/修改/删除 一个事件(事件源fd, 事件类型&ev)</span></div><div class="line"><span class="comment"> * EPOLL_CTL_ADD:注册新的fd到epfd中;</span></div><div class="line"><span class="comment"> * EPOLL_CTL_MOD:修改已经注册的fd的监听事件;</span></div><div class="line"><span class="comment"> * EPOLL_CTL_DEL:从epfd中删除一个fd;</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> ret = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &ev);</div><div class="line"> <span class="comment">//校验</span></div><div class="line"> <span class="keyword">if</span> (ret != <span class="number">0</span>) {</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"epoll_ctl fail:"</span> << ret << <span class="string">",errno:"</span> << errno << <span class="built_in">endl</span>;</div><div class="line"> close(efd);</div><div class="line"> close(epfd);</div><div class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</div><div class="line"> }</div><div class="line"> <span class="comment">//fork一个进程,来读取epoll事件</span></div><div class="line"> <span class="keyword">int</span> pid = fork();</div><div class="line"></div><div class="line"> <span class="keyword">if</span> (pid > <span class="number">0</span>) {<span class="comment">//父进程</span></div><div class="line"> <span class="comment">//监听事件数组</span></div><div class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">epoll_event</span> <span class="title">events</span>[<span class="title">MAXEVENTS</span>];</span></div><div class="line"> <span class="comment">/**</span></div><div class="line"><span class="comment"> * 4. 使用epoll,开始监听事件源,并将事件放置到数组events中</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> * epoll_wait会阻塞当前线程,当监听的事件发生的时候,会唤醒该线程</span></div><div class="line"><span class="comment"> *</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> count = epoll_wait(epfd, events, MAXEVENTS, <span class="number">5000</span>);</div><div class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < count; i++) {</div><div class="line"> <span class="comment">//校验</span></div><div class="line"> <span class="keyword">if</span> ((events[i].data.fd == efd) && (events[<span class="number">0</span>].events & EPOLLIN)) {</div><div class="line"> <span class="keyword">eventfd_t</span> r_num;</div><div class="line"> <span class="keyword">ssize_t</span> size = read(efd, &r_num, <span class="keyword">sizeof</span>(<span class="keyword">eventfd_t</span>));</div><div class="line"> <span class="built_in">printf</span>(<span class="string">"parrent read num is %d bytes data from the eventfd, value is %d \n"</span>, size, r_num);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> close(efd);</div><div class="line"> close(epfd);</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"parent close eventfd and epfd over"</span> << <span class="built_in">endl</span>;</div><div class="line"></div><div class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pid == <span class="number">0</span>) {<span class="comment">//子进程</span></div><div class="line"> <span class="built_in">printf</span>(<span class="string">"sub sleep 3 senconds, and then write\n"</span>);</div><div class="line"> flush(<span class="built_in">cout</span>);</div><div class="line"> <span class="comment">//当前线程睡眠3秒</span></div><div class="line"> sleep(<span class="number">3</span>);</div><div class="line"></div><div class="line"> <span class="comment">//子进程开始向eventfd设备写入数据</span></div><div class="line"> <span class="keyword">eventfd_t</span> num = <span class="number">18</span>;</div><div class="line"> <span class="keyword">if</span> (write(efd, &num, <span class="keyword">sizeof</span>(<span class="keyword">eventfd_t</span>)) == <span class="keyword">sizeof</span>(<span class="keyword">eventfd_t</span>))<span class="comment">//you can remove this line for learn</span></div><div class="line"> <span class="built_in">printf</span>(<span class="string">"sub write num %d, over \n"</span>, num);</div><div class="line"> <span class="comment">//关闭子进程eventfd</span></div><div class="line"> close(efd);<span class="comment">//write</span></div><div class="line"> <span class="built_in">printf</span>(<span class="string">"sub close write eventfd over \n"</span>);</div><div class="line"></div><div class="line"> } <span class="keyword">else</span> { <span class="comment">//pid<0, fork error</span></div><div class="line"> close(efd);</div><div class="line"> close(epfd);</div><div class="line"> <span class="built_in">cout</span> << <span class="string">"fork error:"</span> << pid << <span class="string">", close fds over"</span> << <span class="built_in">endl</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keyword">return</span> <span class="number">0</span>;</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="https://aceld.gitbooks.io/libevent/content/" target="_blank" rel="external">Libevent深入浅出</a><br><br><a href="http://blog.csdn.net/u010657219/article/details/44061629" target="_blank" rel="external">实现机制详解</a><br><br><a href="http://www.cnblogs.com/Anker/p/3263780.html" target="_blank" rel="external">IO多路复用之epoll总结</a><br><br><a href="http://yaocoder.blog.51cto.com/2668309/888374" target="_blank" rel="external">我读过的最好的epoll讲解–转自”知乎“</a><br><br><a href="http://man7.org/linux/man-pages/man2/eventfd.2.html" target="_blank" rel="external">man2:eventfd</a></p>]]></content>
<summary type="html">
<p>epoll 于Linux 2.5.44引入,旨在替换select和poll系统函数。</p>
<p>相对于select和poll来说,epoll更加灵活高效:</p>
<ul>
<li>没有监视描述符数量单进程1024限制</li>
<li>epoll使用一个文件描述符管理
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Linux" scheme="http://www.molingyu.com/tags/Linux/"/>
<category term="C/C++" scheme="http://www.molingyu.com/tags/C-C/"/>
</entry>
<entry>
<title>本博客的建立</title>
<link href="http://www.molingyu.com/2017/09/17/%E6%9C%AC%E5%8D%9A%E5%AE%A2%E7%9A%84%E5%BB%BA%E7%AB%8B/"/>
<id>http://www.molingyu.com/2017/09/17/本博客的建立/</id>
<published>2017-09-16T18:11:22.717Z</published>
<updated>2017-09-16T18:11:22.717Z</updated>
<content type="html"><![CDATA[<p>白驹过隙,工作已有6个春秋</p><p>回望时,竟然没留下些什么</p><p>或心情、或笔录、或歌词、或曲调、或技术历程</p><p>不免感慨万分</p><p>当我老了,至少在这世间留下些什么文字,孤芳自赏也好</p><h2 id="为什么要写博客"><a href="#为什么要写博客" class="headerlink" title="为什么要写博客"></a>为什么要写博客</h2><ul><li>从开始学习Java的时候,曾开博客,将java的课本的知识点一一以自己的理解记录下来</li><li>然后自从工作以来,就渐渐不再更新博客,以至于原博客杂草丛生,无人问津,甚至密码都忘记,那会是在csdn,用的邮箱还是yahoo.com.cn,然后就gg了,再也找不回账号了</li><li>现如今,技术成长和技术驱动,俨然已经跟不上脚步,然年近中年,危机四伏</li><li>写博客作为一种重要的学以致用、朝闻夕记的重要手段,不能荒废丢弃</li><li>以前的学习记录,是该定期整理成文,来督促自己去复习管理</li></ul><h2 id="如何写博客"><a href="#如何写博客" class="headerlink" title="如何写博客"></a>如何写博客</h2><p>本博客的博文</p><ul><li>尽自己所能,还原事物本质</li><li>周期性成文,不可懈怠</li><li>前路漫漫,与君共勉</li></ul><h2 id="如何建立站点"><a href="#如何建立站点" class="headerlink" title="如何建立站点"></a>如何建立站点</h2><p>这个部分,网上已经许多文章</p><ul><li><a href="https://hexo.io/zh-cn/docs/setup.html" target="_blank" rel="external">https://hexo.io/zh-cn/docs/setup.html</a> </li><li><a href="https://linghucong.js.org/2016/04/15/2016-04-15-hexo-github-pages-blog/" target="_blank" rel="external">https://linghucong.js.org/2016/04/15/2016-04-15-hexo-github-pages-blog/</a></li><li><a href="https://github.com/limedroid/HexoLearning" target="_blank" rel="external">https://github.com/limedroid/HexoLearning</a></li></ul><p>我这里主要是提一下npm install遇到的代理问题,很多插件的安装,遇到国墙无法安装,我们需要给npm设置代理才行,<br><a href="https://segmentfault.com/a/1190000002589144" target="_blank" rel="external">参考链接</a>。</p><p>我使用的是Lantern代理,代理的ip和端口,可以从Lanter主页面的Settings的Advance Settins中查看到:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">HTTP(S) proxy : 127.0.0.1:35937</div><div class="line">SOCKS proxy : 127.0.0.1:38185</div></pre></td></tr></table></figure></p><p>因此,在设置代理的时候,采用命令:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">npm config set proxy http://127.0.0.1:35937</div><div class="line">npm config set https-proxy http://127.0.0.1:35937</div></pre></td></tr></table></figure></p><p>后续的插件安装, hexo部署,都能够很顺利的访问</p><h2 id="最后的最后"><a href="#最后的最后" class="headerlink" title="最后的最后"></a>最后的最后</h2><p>路漫漫其修远兮,吾将上下而求索 —— 屈原《离骚》</p>]]></content>
<summary type="html">
<p>白驹过隙,工作已有6个春秋</p>
<p>回望时,竟然没留下些什么</p>
<p>或心情、或笔录、或歌词、或曲调、或技术历程</p>
<p>不免感慨万分</p>
<p>当我老了,至少在这世间留下些什么文字,孤芳自赏也好</p>
<h2 id="为什么要写博客"><a hre
</summary>
<category term="随笔" scheme="http://www.molingyu.com/categories/%E9%9A%8F%E7%AC%94/"/>
<category term="随笔" scheme="http://www.molingyu.com/tags/%E9%9A%8F%E7%AC%94/"/>
</entry>
<entry>
<title>ReentrantLock</title>
<link href="http://www.molingyu.com/2017/09/17/ReentrantLock/"/>
<id>http://www.molingyu.com/2017/09/17/ReentrantLock/</id>
<published>2017-09-16T18:11:19.429Z</published>
<updated>2017-09-16T18:11:19.429Z</updated>
<content type="html"><![CDATA[<p>Java中的可重入锁ReentrantLock很常见,可以用它来代替内置锁synchronized,ReentrantLock是语法级别的锁,所以比内置锁更加灵活。</p><p>ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,默认构造函数采用非公平锁的方式实现。</p><a id="more"></a><h2 id="lock流程"><a href="#lock流程" class="headerlink" title="lock流程"></a>lock流程</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//默认非公平锁</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">()</span> </span>{</div><div class="line"> sync = <span class="keyword">new</span> NonfairSync();</div><div class="line">}</div><div class="line"><span class="comment">//根据fair来初始化使用哪种锁</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">(<span class="keyword">boolean</span> fair)</span> </span>{</div><div class="line"> sync = fair ? <span class="keyword">new</span> FairSync() : <span class="keyword">new</span> NonfairSync();</div><div class="line">}</div><div class="line"><span class="comment">//调用FairSync或者NonfairSync的lock方法,默认sync=NonfairSync</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{</div><div class="line"> sync.lock();</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//1. 首先会通过CAS方法,尝试将当前的java.util.concurrent.locks.AbstractQueuedSynchronizer#state中的state字段改成从0改成1</span></div><div class="line"><span class="comment">/* </span></div><div class="line"><span class="comment"> NonfairSync 继承于 AbstractQueuedSynchronizer, AQS有volatile字段state如下:</span></div><div class="line"><span class="comment"> private volatile int state;</span></div><div class="line"><span class="comment">*/</span></div><div class="line"></div><div class="line"><span class="comment">//2. 如果修改成功,则state锁加锁成功,然后将当前线程通过setExclusiveOwnerThread设置为NonfairSync的独占线程</span></div><div class="line"></div><div class="line"><span class="comment">//3. 否则,就像普通线程一样,acquire(1), 请求加锁</span></div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>))</div><div class="line"> setExclusiveOwnerThread(Thread.currentThread());</div><div class="line"> <span class="keyword">else</span></div><div class="line"> acquire(<span class="number">1</span>);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">//aquire(1)方法</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (!tryAcquire(arg) &&</div><div class="line"> acquireQueued(addWaiter(Node.EXCLUSIVE), arg))</div><div class="line"> selfInterrupt();</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//4. 在tryAcquire(1)中调用nonfairTryAcquire(1)</span></div><div class="line"><span class="comment">//4.1 获取AQS的 state</span></div><div class="line"><span class="comment">//4.1.1 如果c==0,则说明AQS没有加锁,就开始进行CAS操作,成功的化话就setExclusiveOwnerThread,返回true</span></div><div class="line"><span class="comment">//4.1.2 如果c!=0, 则检查当前线程释放为AQS的独占线程,如果是,则int nextc = c + acquires;将state + 1,然后setState(nextc),并返回true</span></div><div class="line"><span class="comment">//否则返回false</span></div><div class="line"><span class="comment">//PS: 这里的CAS操作,是调用Unsafe类的compareAndSwapInt通过native直接郊游系统操作CPU完成的</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</div><div class="line"> <span class="keyword">return</span> nonfairTryAcquire(acquires);</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">nonfairTryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</div><div class="line"> <span class="keyword">final</span> Thread current = Thread.currentThread();</div><div class="line"> <span class="keyword">int</span> c = getState();</div><div class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>) {</div><div class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, acquires)) {</div><div class="line"> setExclusiveOwnerThread(current);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) {</div><div class="line"> <span class="keyword">int</span> nextc = c + acquires;</div><div class="line"> <span class="keyword">if</span> (nextc < <span class="number">0</span>) <span class="comment">// overflow</span></div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Maximum lock count exceeded"</span>);</div><div class="line"> setState(nextc);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//5. 如果4的!tryAcquire()成立,即tryAcquire失败,则开始 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)</span></div><div class="line"><span class="comment">//5.1 首先 addWaiter(Node.EXCLUSIVE),将当前线程添加到AQS的队列中:</span></div><div class="line"><span class="comment">//(1)首先创建一个为独占模式的Node,</span></div><div class="line"><span class="comment">//(2)再判断一下队列上有没有结点,没有就创建一个空结点头,然后将Node添加到末尾,创建和添加凑采用的是AQS的CAS操作,保证可见性</span></div><div class="line"><span class="function"><span class="keyword">private</span> Node <span class="title">addWaiter</span><span class="params">(Node mode)</span> </span>{</div><div class="line"> Node node = <span class="keyword">new</span> Node(Thread.currentThread(), mode);</div><div class="line"> <span class="comment">// Try the fast path of enq; backup to full enq on failure</span></div><div class="line"> Node pred = tail;</div><div class="line"> <span class="keyword">if</span> (pred != <span class="keyword">null</span>) {</div><div class="line"> node.prev = pred;</div><div class="line"> <span class="keyword">if</span> (compareAndSetTail(pred, node)) {</div><div class="line"> pred.next = node;</div><div class="line"> <span class="keyword">return</span> node;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> enq(node);</div><div class="line"> <span class="keyword">return</span> node;</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//5.2 acquireQueued</span></div><div class="line"><span class="comment">//(1)首先判断node是不是队列第一个,如果是、且尝试获取锁成功,则将node设成head,并把此前的head.next=null,帮助gc回收</span></div><div class="line"><span class="comment">//(2)如果node不是队列第一个,或者获取锁不成功(其他线程还没释放),则进入shouldParkAfterFailedAcquire方法</span></div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">acquireQueued</span><span class="params">(<span class="keyword">final</span> Node node, <span class="keyword">int</span> arg)</span> </span>{</div><div class="line"> <span class="keyword">boolean</span> failed = <span class="keyword">true</span>;</div><div class="line"> <span class="keyword">try</span> {</div><div class="line"> <span class="keyword">boolean</span> interrupted = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">for</span> (;;) {</div><div class="line"> <span class="keyword">final</span> Node p = node.predecessor();</div><div class="line"> <span class="keyword">if</span> (p == head && tryAcquire(arg)) {</div><div class="line"> setHead(node);</div><div class="line"> p.next = <span class="keyword">null</span>; <span class="comment">// help GC</span></div><div class="line"> failed = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">return</span> interrupted;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (shouldParkAfterFailedAcquire(p, node) &&</div><div class="line"> parkAndCheckInterrupt())</div><div class="line"> interrupted = <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> } <span class="keyword">finally</span> {</div><div class="line"> <span class="keyword">if</span> (failed)</div><div class="line"> cancelAcquire(node);</div><div class="line"> }</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//5.2.1 shouldParkAfterFailedAcquire</span></div><div class="line"><span class="comment">//(1)首次进来,waitStatus肯定为0,那么设置为SIGNAL,并立即返回false。然后返回acquireQueued方法,继续走for循环,再一次尝试获取锁,不成功继续走shouldParkAfterFailedAcquire方法,此时waitStatus=-1,因此这里直接走第一个if,返回true。</span></div><div class="line"><span class="comment">//(2)然后开始走parkAndCheckInterrupt方法</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">boolean</span> <span class="title">shouldParkAfterFailedAcquire</span><span class="params">(Node pred, Node node)</span> </span>{</div><div class="line"> <span class="keyword">int</span> ws = pred.waitStatus;</div><div class="line"> <span class="keyword">if</span> (ws == Node.SIGNAL)</div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * This node has already set status asking a release</span></div><div class="line"><span class="comment"> * to signal it, so it can safely park.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> <span class="keyword">if</span> (ws > <span class="number">0</span>) {</div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * Predecessor was cancelled. Skip over predecessors and</span></div><div class="line"><span class="comment"> * indicate retry.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">do</span> {</div><div class="line"> node.prev = pred = pred.prev;</div><div class="line"> } <span class="keyword">while</span> (pred.waitStatus > <span class="number">0</span>);</div><div class="line"> pred.next = node;</div><div class="line"> } <span class="keyword">else</span> {</div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * waitStatus must be 0 or PROPAGATE. Indicate that we</span></div><div class="line"><span class="comment"> * need a signal, but don't park yet. Caller will need to</span></div><div class="line"><span class="comment"> * retry to make sure it cannot acquire before parking.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> compareAndSetWaitStatus(pred, ws, Node.SIGNAL);</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">}</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//5.2.2 parkAndCheckInterrupt</span></div><div class="line"><span class="comment">//(1)调用LockSupport的park方法阻塞住了当前的线程</span></div><div class="line"><span class="comment">//(2)至此,使用ReentrantLock让线程1独占锁、线程2进入FIFO队列并阻塞的完整流程已经整理出来了</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">parkAndCheckInterrupt</span><span class="params">()</span> </span>{</div><div class="line"> LockSupport.park(<span class="keyword">this</span>);</div><div class="line"> <span class="keyword">return</span> Thread.interrupted();</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">park</span><span class="params">(Object blocker)</span> </span>{</div><div class="line"> Thread t = Thread.currentThread();</div><div class="line"> setBlocker(t, blocker);</div><div class="line"> UNSAFE.park(<span class="keyword">false</span>, <span class="number">0L</span>);</div><div class="line"> setBlocker(t, <span class="keyword">null</span>);</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="unlock流程"><a href="#unlock流程" class="headerlink" title="unlock流程"></a>unlock流程</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//走AQS(AbstractQueuedSynchronizer)的release流程</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unlock</span><span class="params">()</span> </span>{</div><div class="line"> sync.release(<span class="number">1</span>);</div><div class="line">}</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">release</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</div><div class="line"> <span class="keyword">if</span> (tryRelease(arg)) {</div><div class="line"> Node h = head;</div><div class="line"> <span class="keyword">if</span> (h != <span class="keyword">null</span> && h.waitStatus != <span class="number">0</span>)</div><div class="line"> unparkSuccessor(h);</div><div class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">}</div><div class="line"><span class="comment">//先调用tryRelease尝试释放锁</span></div><div class="line"><span class="comment">//首先,只有当c==0的时候才会让free=true,这和上面一个线程多次调用lock方法累加state是对应的,调用了多少次的lock()方法自然必须调用同样次数的unlock()方法才行,这样才把一个锁给全部解开。</span></div><div class="line"><span class="comment">//当一条线程对同一个ReentrantLock全部解锁之后,AQS的state自然就是0了,AbstractOwnableSynchronizer的exclusiveOwnerThread将被设置为null,这样就表示没有线程占有锁,方法返回true。</span></div><div class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryRelease</span><span class="params">(<span class="keyword">int</span> releases)</span> </span>{</div><div class="line"> <span class="keyword">int</span> c = getState() - releases;</div><div class="line"> <span class="keyword">if</span> (Thread.currentThread() != getExclusiveOwnerThread())</div><div class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalMonitorStateException();</div><div class="line"> <span class="keyword">boolean</span> free = <span class="keyword">false</span>;</div><div class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>) {</div><div class="line"> free = <span class="keyword">true</span>;</div><div class="line"> setExclusiveOwnerThread(<span class="keyword">null</span>);</div><div class="line"> }</div><div class="line"> setState(c);</div><div class="line"> <span class="keyword">return</span> free;</div><div class="line">}</div><div class="line"><span class="comment">//代码继续往下走,上面的release方法的第四行,h不为null成立,h的waitStatus为-1,不等于0也成立,所以走第5行的unparkSuccessor方法:</span></div><div class="line"><span class="comment">//s即h的下一个Node,这个Node里面的线程就是线程2,由于这个Node不等于null,所以走21行,线程2被unPark了,得以运行。</span></div><div class="line"><span class="comment">//有一个很重要的问题是:锁被解了怎样保证整个FIFO队列减少一个Node呢?这是一个很巧妙的设计,又回到了AQS的acquireQueued方法了:</span></div><div class="line"><span class="comment">//阻塞完成线程2依然会进行for循环。然后,阻塞完成了,线程2所在的Node的前驱Node是p,线程2尝试tryAcquire,成功,然后线程2就成为了head节点了,把p的next设置为null,这样原头Node里面的所有对象都不指向任何块内存空间,h属于栈内存的内容,方法结束被自动回收,这样随着方法的调用完毕,原头Node也没有任何的引用指向它了,这样它就被GC自动回收了。此时,遇到一个return语句,acquireQueued方法结束,后面的Node也是一样的原理。</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">unparkSuccessor</span><span class="params">(Node node)</span> </span>{</div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * If status is negative (i.e., possibly needing signal) try</span></div><div class="line"><span class="comment"> * to clear in anticipation of signalling. It is OK if this</span></div><div class="line"><span class="comment"> * fails or if status is changed by waiting thread.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> <span class="keyword">int</span> ws = node.waitStatus;</div><div class="line"> <span class="keyword">if</span> (ws < <span class="number">0</span>)</div><div class="line"> compareAndSetWaitStatus(node, ws, <span class="number">0</span>);</div><div class="line"></div><div class="line"> <span class="comment">/*</span></div><div class="line"><span class="comment"> * Thread to unpark is held in successor, which is normally</span></div><div class="line"><span class="comment"> * just the next node. But if cancelled or apparently null,</span></div><div class="line"><span class="comment"> * traverse backwards from tail to find the actual</span></div><div class="line"><span class="comment"> * non-cancelled successor.</span></div><div class="line"><span class="comment"> */</span></div><div class="line"> Node s = node.next;</div><div class="line"> <span class="keyword">if</span> (s == <span class="keyword">null</span> || s.waitStatus > <span class="number">0</span>) {</div><div class="line"> s = <span class="keyword">null</span>;</div><div class="line"> <span class="keyword">for</span> (Node t = tail; t != <span class="keyword">null</span> && t != node; t = t.prev)</div><div class="line"> <span class="keyword">if</span> (t.waitStatus <= <span class="number">0</span>)</div><div class="line"> s = t;</div><div class="line"> }</div><div class="line"> <span class="keyword">if</span> (s != <span class="keyword">null</span>)</div><div class="line"> LockSupport.unpark(s.thread);</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="公平锁-与-非公平锁"><a href="#公平锁-与-非公平锁" class="headerlink" title="公平锁 与 非公平锁"></a>公平锁 与 非公平锁</h2><h3 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//一上来就进入普通跟拿锁流程:加入队列中,按照lock顺序获得锁。排队,公平</span></div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{</div><div class="line"> acquire(<span class="number">1</span>);</div><div class="line">}</div></pre></td></tr></table></figure><h3 id="非公平锁"><a href="#非公平锁" class="headerlink" title="非公平锁"></a>非公平锁</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="comment">//上来就拿锁,拿不再进入普通拿锁流程,插队,不公平</span></div><div class="line"><span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{</div><div class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>))</div><div class="line"> setExclusiveOwnerThread(Thread.currentThread());</div><div class="line"> <span class="keyword">else</span></div><div class="line"> acquire(<span class="number">1</span>);</div><div class="line">}</div></pre></td></tr></table></figure><h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><p><a href="http://www.cnblogs.com/szlbm/p/5505698.html" target="_blank" rel="external">http://www.cnblogs.com/szlbm/p/5505698.html</a></p><p><a href="http://www.cnblogs.com/wanly3643/p/3835839.html" target="_blank" rel="external">http://www.cnblogs.com/wanly3643/p/3835839.html</a></p>]]></content>
<summary type="html">
<p>Java中的可重入锁ReentrantLock很常见,可以用它来代替内置锁synchronized,ReentrantLock是语法级别的锁,所以比内置锁更加灵活。</p>
<p>ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,默认构造函数采用非公平锁的方式实现。</p>
</summary>
<category term="学习笔记" scheme="http://www.molingyu.com/categories/%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/"/>
<category term="Java" scheme="http://www.molingyu.com/tags/Java/"/>
</entry>
</feed>