版权声明:本文为博主原创文章,未经博主允许不得转载。
刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会阻塞主线程的。长时间就直接ANR了。
我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。
这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。
关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。
启动一个Service只需调用Context的startService方法,传进一个Intent即可。看起来好像很简单的说,那是因为Android为了方便开发者,做了很大程度的封装。那么你真的有去学习过Service是怎么启动的吗?Service的onCreate方法回调前都做了哪些准备工作?
先上一张图大致了解下,灰色背景框起来的是同一个类中的方法,如下图:
那接下来就从源码的角度来分析Service的启动过程。
当然是从Context的startService方法开始,Context的实现类是ContextImpl,那么我们就看到ContextImpl的startService方法即可,如下:
<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> ComponentName <span class="hljs-title">startService</span>(Intent service) {
warnIfCallingFromSystemProcess();
<span class="hljs-keyword">return</span> startServiceCommon(service, mUser);
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
会转到startServiceCommon方法,那跟进startServiceCommon方法方法瞧瞧。
<code class="hljs cs has-numbering"><span class="hljs-keyword">private</span> ComponentName <span class="hljs-title">startServiceCommon</span>(Intent service, UserHandle user) {
<span class="hljs-keyword">try</span> {
validateServiceIntent(service);
service.prepareToLeaveProcess();
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), getOpPackageName(), user.getIdentifier());
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">return</span> cn;
} <span class="hljs-keyword">catch</span> (RemoteException e) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"Failure from system"</span>, e);
}
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li></ul>
可以看到调用了ActivityManagerNative.getDefault()的startService方法来启动Service,ActivityManagerNative.getDefault()是ActivityManagerService,简称AMS。
那么现在启动Service的过程就转移到了ActivityManagerService,我们关注ActivityManagerService的startService方法即可,如下:
<code class="hljs java has-numbering"><span class="hljs-annotation">@Override</span>
<span class="hljs-keyword">public</span> ComponentName <span class="hljs-title">startService</span>(IApplicationThread caller, Intent service,
String resolvedType, String callingPackage, <span class="hljs-keyword">int</span> userId)
<span class="hljs-keyword">throws</span> TransactionTooLargeException {
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">synchronized</span>(<span class="hljs-keyword">this</span>) {
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> callingPid = Binder.getCallingPid();
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> callingUid = Binder.getCallingUid();
<span class="hljs-keyword">final</span> <span class="hljs-keyword">long</span> origId = Binder.clearCallingIdentity();
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, callingPackage, userId);
Binder.restoreCallingIdentity(origId);
<span class="hljs-keyword">return</span> res;
}
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li></ul>
在上述的代码中,调用了ActiveServices的startServiceLocked方法,那么现在Service的启动过程从AMS转移到了ActiveServices了。
继续跟进ActiveServices的startServiceLocked方法,如下:
<code class="hljs java has-numbering">ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
<span class="hljs-keyword">int</span> callingPid, <span class="hljs-keyword">int</span> callingUid, String callingPackage, <span class="hljs-keyword">int</span> userId)
<span class="hljs-keyword">throws</span> TransactionTooLargeException {
<span class="hljs-comment">//代码省略</span>
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType, callingPackage,
callingPid, callingUid, userId, <span class="hljs-keyword">true</span>, callerFg);
<span class="hljs-comment">//代码省略</span>
ServiceRecord r = res.record;
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">return</span> startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li></ul>
在startServiceLocked方法中又会调用startServiceInnerLocked方法,
我们瞧瞧startServiceInnerLocked方法,
<code class="hljs avrasm has-numbering">ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
ProcessStats<span class="hljs-preprocessor">.ServiceState</span> stracker = r<span class="hljs-preprocessor">.getTracker</span>()<span class="hljs-comment">;</span>
if (stracker != null) {
stracker<span class="hljs-preprocessor">.setStarted</span>(true, mAm<span class="hljs-preprocessor">.mProcessStats</span><span class="hljs-preprocessor">.getMemFactorLocked</span>(), r<span class="hljs-preprocessor">.lastActivity</span>)<span class="hljs-comment">;</span>
}
r<span class="hljs-preprocessor">.callStart</span> = false<span class="hljs-comment">;</span>
synchronized (r<span class="hljs-preprocessor">.stats</span><span class="hljs-preprocessor">.getBatteryStats</span>()) {
r<span class="hljs-preprocessor">.stats</span><span class="hljs-preprocessor">.startRunningLocked</span>()<span class="hljs-comment">;</span>
}
String error = bringUpServiceLocked(r, service<span class="hljs-preprocessor">.getFlags</span>(), callerFg, false)<span class="hljs-comment">;</span>
//代码省略
return r<span class="hljs-preprocessor">.name</span><span class="hljs-comment">;</span>
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul>
startServiceInnerLocked方法内部调用了bringUpServiceLocked方法,此时启动过程已经快要离开ActiveServices了。继续看到bringUpServiceLocked方法。如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String <span class="hljs-title">bringUpServiceLocked</span>(ServiceRecord r, <span class="hljs-keyword">int</span> intentFlags, <span class="hljs-keyword">boolean</span> execInFg,
<span class="hljs-keyword">boolean</span> whileRestarting) <span class="hljs-keyword">throws</span> TransactionTooLargeException {
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">if</span> (app != <span class="hljs-keyword">null</span> && app.thread != <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">try</span> {
app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li></ul>
省略了大部分if判断,相信眼尖的你一定发现了核心的方法,那就是
realStartServiceLocked,没错,看名字就像是真正启动Service。那么事不宜迟跟进去探探吧。如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">realStartServiceLocked</span>(ServiceRecord r,
ProcessRecord app, <span class="hljs-keyword">boolean</span> execInFg) <span class="hljs-keyword">throws</span> RemoteException {
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">boolean</span> created = <span class="hljs-keyword">false</span>;
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">//代码省略</span>
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = <span class="hljs-keyword">true</span>;
} <span class="hljs-keyword">catch</span> (DeadObjectException e) {
Slog.w(TAG, <span class="hljs-string">"Application dead when creating service "</span> + r);
mAm.appDiedLocked(app);
<span class="hljs-keyword">throw</span> e;
}
<span class="hljs-comment">//代码省略</span>
sendServiceArgsLocked(r, execInFg, <span class="hljs-keyword">true</span>);
<span class="hljs-comment">//代码省略</span>
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li></ul>
找到了。app.thread调用了scheduleCreateService来启动Service,而app.thread是一个ApplicationThread,也是ActivityThread的内部类。此时已经到了主线程。
那么我们探探ApplicationThread的scheduleCreateService方法。如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">scheduleCreateService</span>(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, <span class="hljs-keyword">int</span> processState) {
updateProcessState(processState, <span class="hljs-keyword">false</span>);
CreateServiceData s = <span class="hljs-keyword">new</span> CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li></ul>
对待启动的Service组件信息进行包装,然后发送了一个消息。我们关注这个CREATE_SERVICE消息即可。
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) {
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">case</span> CREATE_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="hljs-string">"serviceCreate"</span>);
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
<span class="hljs-keyword">break</span>;
<span class="hljs-comment">//代码省略</span>
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>
在handleMessage方法中接收到这个消息,然后调用了handleCreateService方法,跟进handleCreateService探探究竟:
<code class="hljs avrasm has-numbering">private void handleCreateService(CreateServiceData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler()<span class="hljs-comment">;</span>
LoadedApk packageInfo = getPackageInfoNoCheck(
data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.applicationInfo</span>, data<span class="hljs-preprocessor">.compatInfo</span>)<span class="hljs-comment">;</span>
Service service = null<span class="hljs-comment">;</span>
try {
java<span class="hljs-preprocessor">.lang</span><span class="hljs-preprocessor">.ClassLoader</span> cl = packageInfo<span class="hljs-preprocessor">.getClassLoader</span>()<span class="hljs-comment">;</span>
service = (Service) cl<span class="hljs-preprocessor">.loadClass</span>(data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>)<span class="hljs-preprocessor">.newInstance</span>()<span class="hljs-comment">;</span>
} catch (Exception e) {
if (!mInstrumentation<span class="hljs-preprocessor">.onException</span>(service, e)) {
throw new RuntimeException(
<span class="hljs-string">"Unable to instantiate service "</span> + data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>
+ <span class="hljs-string">": "</span> + e<span class="hljs-preprocessor">.toString</span>(), e)<span class="hljs-comment">;</span>
}
}
try {
if (localLOGV) Slog<span class="hljs-preprocessor">.v</span>(TAG, <span class="hljs-string">"Creating service "</span> + data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>)<span class="hljs-comment">;</span>
ContextImpl context = ContextImpl<span class="hljs-preprocessor">.createAppContext</span>(this, packageInfo)<span class="hljs-comment">;</span>
context<span class="hljs-preprocessor">.setOuterContext</span>(service)<span class="hljs-comment">;</span>
Application app = packageInfo<span class="hljs-preprocessor">.makeApplication</span>(false, mInstrumentation)<span class="hljs-comment">;</span>
service<span class="hljs-preprocessor">.attach</span>(context, this, data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>, data<span class="hljs-preprocessor">.token</span>, app,
ActivityManagerNative<span class="hljs-preprocessor">.getDefault</span>())<span class="hljs-comment">;</span>
service<span class="hljs-preprocessor">.onCreate</span>()<span class="hljs-comment">;</span>
mServices<span class="hljs-preprocessor">.put</span>(data<span class="hljs-preprocessor">.token</span>, service)<span class="hljs-comment">;</span>
try {
ActivityManagerNative<span class="hljs-preprocessor">.getDefault</span>()<span class="hljs-preprocessor">.serviceDoneExecuting</span>(
data<span class="hljs-preprocessor">.token</span>, SERVICE_DONE_EXECUTING_ANON, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)<span class="hljs-comment">;</span>
} catch (RemoteException e) {
// nothing to do.
}
} catch (Exception e) {
if (!mInstrumentation<span class="hljs-preprocessor">.onException</span>(service, e)) {
throw new RuntimeException(
<span class="hljs-string">"Unable to create service "</span> + data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>
+ <span class="hljs-string">": "</span> + e<span class="hljs-preprocessor">.toString</span>(), e)<span class="hljs-comment">;</span>
}
}
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li></ul>
终于击破,这个方法很核心的。一点点分析
首先获取到一个LoadedApk对象,在通过这个LoadedApk对象获取到一个类加载器,通过这个类加载器来创建Service。如下:
<code class="hljs avrasm has-numbering">java<span class="hljs-preprocessor">.lang</span><span class="hljs-preprocessor">.ClassLoader</span> cl = packageInfo<span class="hljs-preprocessor">.getClassLoader</span>()<span class="hljs-comment">;</span>
service = (Service) cl<span class="hljs-preprocessor">.loadClass</span>(data<span class="hljs-preprocessor">.info</span><span class="hljs-preprocessor">.name</span>)<span class="hljs-preprocessor">.newInstance</span>()<span class="hljs-comment">;</span>
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
接着调用ContextImpl的createAppContext方法创建了一个ContextImpl对象。
之后再调用LoadedApk的makeApplication方法来创建Application,这个创建过程如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> Application <span class="hljs-title">makeApplication</span>(<span class="hljs-keyword">boolean</span> forceDefaultAppClass,
Instrumentation instrumentation) {
<span class="hljs-keyword">if</span> (mApplication != <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">return</span> mApplication;
}
Application app = <span class="hljs-keyword">null</span>;
String appClass = mApplicationInfo.className;
<span class="hljs-keyword">if</span> (forceDefaultAppClass || (appClass == <span class="hljs-keyword">null</span>)) {
appClass = <span class="hljs-string">"android.app.Application"</span>;
}
<span class="hljs-keyword">try</span> {
java.lang.ClassLoader cl = getClassLoader();
<span class="hljs-keyword">if</span> (!mPackageName.equals(<span class="hljs-string">"android"</span>)) {
initializeJavaContextClassLoader();
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, <span class="hljs-keyword">this</span>);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">if</span> (!mActivityThread.mInstrumentation.onException(app, e)) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(
<span class="hljs-string">"Unable to instantiate application "</span> + appClass
+ <span class="hljs-string">": "</span> + e.toString(), e);
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
<span class="hljs-keyword">if</span> (instrumentation != <span class="hljs-keyword">null</span>) {
<span class="hljs-keyword">try</span> {
instrumentation.callApplicationOnCreate(app);
} <span class="hljs-keyword">catch</span> (Exception e) {
<span class="hljs-keyword">if</span> (!instrumentation.onException(app, e)) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(
<span class="hljs-string">"Unable to create application "</span> + app.getClass().getName()
+ <span class="hljs-string">": "</span> + e.toString(), e);
}
}
}
<span class="hljs-comment">// Rewrite the R 'constants' for all library apks.</span>
SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
.getAssignedPackageIdentifiers();
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> N = packageIdentifiers.size();
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < N; i++) {
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> id = packageIdentifiers.keyAt(i);
<span class="hljs-keyword">if</span> (id == <span class="hljs-number">0x01</span> || id == <span class="hljs-number">0x7f</span>) {
<span class="hljs-keyword">continue</span>;
}
rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
}
<span class="hljs-keyword">return</span> app;
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li><li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li><li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li><li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li><li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li><li>60</li></ul>
当然Application是只有一个的,从上述代码中也可以看出。
在回来继续看handleCreateService方法,之后service调用了attach方法关联了ContextImpl和Application等
最后service回调了onCreate方法,
<code class="hljs avrasm has-numbering">service<span class="hljs-preprocessor">.onCreate</span>()<span class="hljs-comment">;</span>
mServices<span class="hljs-preprocessor">.put</span>(data<span class="hljs-preprocessor">.token</span>, service)<span class="hljs-comment">;</span>
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li></ul>
并将这个service添加进了一个了列表进行管理。
至此service启动了起来,以上就是service的启动过程。
你可能还想要知道onStartCommand方法是怎么被回调的?可能细心的你发现了在ActiveServices的realStartServiceLocked方法中,那里还有一个sendServiceArgsLocked方法。是的,那个就是入口。
那么我们跟进sendServiceArgsLocked方法看看onStartCommand方法是怎么回调的。
<code class="hljs java has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sendServiceArgsLocked</span>(ServiceRecord r, <span class="hljs-keyword">boolean</span> execInFg,
<span class="hljs-keyword">boolean</span> oomAdjusted) <span class="hljs-keyword">throws</span> TransactionTooLargeException {
<span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> N = r.pendingStarts.size();
<span class="hljs-comment">//代码省略</span>
<span class="hljs-keyword">try</span> {
<span class="hljs-comment">//代码省略</span>
r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} <span class="hljs-keyword">catch</span> (TransactionTooLargeException e) {
<span class="hljs-keyword">if</span> (DEBUG_SERVICE) Slog.v(TAG_SERVICE, <span class="hljs-string">"Transaction too large: intent="</span>
+ si.intent);
caughtException = e;
} <span class="hljs-keyword">catch</span> (RemoteException e) {
<span class="hljs-comment">// Remote process gone... we'll let the normal cleanup take care of this.</span>
<span class="hljs-keyword">if</span> (DEBUG_SERVICE) Slog.v(TAG_SERVICE, <span class="hljs-string">"Crashed while sending args: "</span> + r);
caughtException = e;
}
<span class="hljs-comment">//代码省略</span>
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li></ul>
可以看到onStartCommand方法回调过程和onCreate方法的是很相似的,都会转到app.thread。那么现在就跟进ApplicationThread的scheduleServiceArgs。
你也可能猜到了应该又是封装一些Service的信息,然后发送一个消息, handleMessage接收。是的,源码如下:
<code class="hljs java has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">scheduleServiceArgs</span>(IBinder token, <span class="hljs-keyword">boolean</span> taskRemoved, <span class="hljs-keyword">int</span> startId,
<span class="hljs-keyword">int</span> flags ,Intent args) {
ServiceArgsData s = <span class="hljs-keyword">new</span> ServiceArgsData();
s.token = token;
s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
sendMessage(H.SERVICE_ARGS, s);
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li></ul>
<code class="hljs cs has-numbering"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">handleMessage</span>(Message msg) { <span class="hljs-comment">//代码省略</span> <span class="hljs-keyword">case</span> SERVICE_ARGS: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, <span class="hljs-string">"serviceStart"</span>); handleServiceArgs((ServiceArgsData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); <span class="hljs-keyword">break</span>; <span class="hljs-comment">//代码省略</span>}</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul><div class="save_code tracking-ad" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>
咦,真的是这样。谜底应该就在handleServiceArgs方法了,那么赶紧瞧瞧,源码如下:
<code class="hljs avrasm has-numbering">private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices<span class="hljs-preprocessor">.get</span>(data<span class="hljs-preprocessor">.token</span>)<span class="hljs-comment">;</span>
if (s != null) {
try {
if (data<span class="hljs-preprocessor">.args</span> != null) {
data<span class="hljs-preprocessor">.args</span><span class="hljs-preprocessor">.setExtrasClassLoader</span>(s<span class="hljs-preprocessor">.getClassLoader</span>())<span class="hljs-comment">;</span>
data<span class="hljs-preprocessor">.args</span><span class="hljs-preprocessor">.prepareToEnterProcess</span>()<span class="hljs-comment">;</span>
}
int res<span class="hljs-comment">;</span>
if (!data<span class="hljs-preprocessor">.taskRemoved</span>) {
res = s<span class="hljs-preprocessor">.onStartCommand</span>(data<span class="hljs-preprocessor">.args</span>, data<span class="hljs-preprocessor">.flags</span>, data<span class="hljs-preprocessor">.startId</span>)<span class="hljs-comment">;</span>
} else {
s<span class="hljs-preprocessor">.onTaskRemoved</span>(data<span class="hljs-preprocessor">.args</span>)<span class="hljs-comment">;</span>
res = Service<span class="hljs-preprocessor">.START</span>_TASK_REMOVED_COMPLETE<span class="hljs-comment">;</span>
}
QueuedWork<span class="hljs-preprocessor">.waitToFinish</span>()<span class="hljs-comment">;</span>
try {
ActivityManagerNative<span class="hljs-preprocessor">.getDefault</span>()<span class="hljs-preprocessor">.serviceDoneExecuting</span>(
data<span class="hljs-preprocessor">.token</span>, SERVICE_DONE_EXECUTING_START, data<span class="hljs-preprocessor">.startId</span>, res)<span class="hljs-comment">;</span>
} catch (RemoteException e) {
// nothing to do.
}
ensureJitEnabled()<span class="hljs-comment">;</span>
} catch (Exception e) {
if (!mInstrumentation<span class="hljs-preprocessor">.onException</span>(s, e)) {
throw new RuntimeException(
<span class="hljs-string">"Unable to start service "</span> + s
+ <span class="hljs-string">" with "</span> + data<span class="hljs-preprocessor">.args</span> + <span class="hljs-string">": "</span> + e<span class="hljs-preprocessor">.toString</span>(), e)<span class="hljs-comment">;</span>
}
}
}
}
</code><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul><div class="save_code tracking-ad" style="display: none;" data-mod="popu_249"><a target=_blank target="_blank"><img src="http://static.blog.csdn.net/images/save_snippets.png" alt="" /></a></div><ul class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul>
可以看到回调了onStartCommand方法。
以上就是Service的启动过程的源码分析。
从中,我理解了Service的启动过程的同时,阅读源码的能力也提高了,分析源码的时候我没能力把每一个变量,每一个方法都搞懂,我关注的都是一些关键的字眼,比如这篇文章就是start呀,service呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。
这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。