Android Service的启动过程

来源:互联网 发布:js动态生成商品表格 编辑:程序博客网 时间:2024/06/06 00:18

刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会阻塞主线程的。长时间就直接ANR了。

我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。
这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。

关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。
启动一个Service只需调用Context的startService方法,传进一个Intent即可。看起来好像很简单的说,那是因为Android为了方便开发者,做了很大程度的封装。那么你真的有去学习过Service是怎么启动的吗?Service的onCreate方法回调前都做了哪些准备工作?

先上一张图大致了解下,灰色背景框起来的是同一个类中的方法,如下图:
Service启动过程

那接下来就从源码的角度来分析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呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。

这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。

0 0