Service的工作过程

Service启动过程

service启动过程
  • Service的启动过程从ContextWrapper的startService方法开始

    public ComponentName startService(Intent service) {
        return mBase.startService(service);
    }
    

    mBase的类型是<code>ContextImpl</code>,在Activity创建时会通过<code>attach</code>方法将ContextImpl对象关联起来,ContextWrapper的大部分操作都是mBase来实现的,这种模式叫桥接模式.

  • 在ContextImpl中,startService方法会调用<code>startServiceCommon</code>方法,而该方法会用过<code>ActivityManagerNative.getDefault()</code>对象来启动一个服务,也就是AMS,通过AMS来启动服务的行为是一个远程过程调用。

  • 在AMS中会通过<code>mServices</code>这个对象完成后续的启动过程,mService对象的类型是<code>ActivityService</code>

    ActivityService:辅助AMS进行Service管理的类。包括Service启动、绑定、停止等。

  • 在<code>ActivityService</code>方法最后会调用<code>startServiceInnerLocked</code>方法

  • <code>startServiceInnerLocked</code>方法并没有完成具体的启动工作,而是把后续的工作交给了<code>bringUpServiceLocked</code>来处理,在该方法中又调用了<code>realStartServiceLocked</code>方法。

  • <code>realStartServiceLocked</code>方法中(两个过程均是进程通信)

    • 首先是通过<code>app.thread</code>的<code>scheduleCreateService</code>方法来创建Service并调用其onCreate

    <code>app.thread</code>是<code>IApplicationThread</code>类型,它实际上是一个Binder,具体实现是<code>ApplicationThread</code>和<code>ApplicationThreadNative</code>,而前者是继承于后者,因此,只需要看<code>ApplicationThread</code>对Service启动过程的处理即可,对应着<code>scheduleCreateService</code>方法。
    这个过程和Activity的启动过程是类似,通过发送消息给Handler H来完成。H接收CREATE_SERVICE消息并通过<code>handlerCreateService</code>来完成Service的最终启动。

          handlerCreateService方法主要做了这几件事
          
          1.通过类加载器创建Service的实例
          2.创建Application对象并调用其onCreate方法(创建过程只会有一次)
          3.创建ConTextImpl对象并通过Service的attach方法建立二者的关系
          4.最后调用Service的onCreate方法并将Service对象存储到ActivityThread中的一个列表中.
    
  • 接着通过<code>sendServiceArgsLocked</code>方法来调用Service的其他方法,比如onStartCommand(ActivityThread通过<code>handleServiceArgs</code>方法调用Service的onStartCommand方法。)


Service绑定过程

service绑定过程
  • 和Service启动过程一样,它的绑定过程也是从ContextWrapper开始的。
public boolean bindService(Intent service, ServiceConnection conn,
           int flags) {
    return mBase.bindService(service, conn, flags);
}
  • mBase同样是ContextImpl类型的对象,mBase的<code>bindService</code>方法最终会调用自己的<code>bindServiceCommon</code>方法

    <code>bindServiceCommon</code>方法主要完成如下两件事:

    1. 将客户端的ServiceConnection对象转化为ServiceDispatcher.IServiceConnection对象。

    之所以不能直接使用<code>ServiceConnection</code>对象是因为服务的绑定可能是跨进程的,因此ServiceConnection对象必须借助Binder才能让远程服务端回调自己的方法,而<code>ServiceDispatcher</code>的内部类<code>IServiceConnection</code>刚好充当了Binder这个角色。

    > <code>ServiceDispatcher</code>起着连接SercviceConnection和InnerConnection的作用,这个过程由LoadedApk的<code>getServiceDispatcher</code>方法来完成
    
    > <code>mServices</code>是一个<code>ArrayMap</code>,它存储了一个应用当前活动的ServiceConnection和ServiceDispatcher的映射关系。
    
    1. <code>bindServiceCommon</code>方法会通过AMS完成Service的具体绑定过程.

    AMS调用ActiveServicesd的<code>bindServiceLocked</code>方法,而该方法再调用bindUpServiceLocked方法,<code>bindUpServiceLocked</code>方法又会调用<code>realStartServiceLocked</code>方法

      > <code>realStartServiceLocked</code>的执行逻辑和启动的逻辑类似,都是通过ApplicationThread来完成Service的创建并执行onCreate方法。
      **和启动Service不同的是**,Service的绑定过程会调用app.thread的<code>scheduleBindService</code>方法,这个过程的实现在ActivityService的<code>requestServiceBindingLocked</code>方法。
      
      ApplicationThread的一系列以schedule开头的方法,内部都是通过Handler H中转的。在H内部接收到BIND_SERVICE这类消息时,会交给ActivityThread的<code>handleBindService</code>方法来处理.在该方法中会根据Service的token取出Service对象,然后调用onBind方法.onBind方法会返回一个Binder对象给客户端使用.原则上此时已经属于绑定状态了,但是**onBind方法是Service的方法,这个时候客户端并不知道已经成功连接了**,所以还必须调用客户端的<code>ServiceConnection</code>中的<code>onServiceConnected</code>(这个过程由ActivityManagerNative.getDefault()的<code>publishService</code>方法来完成的)
    
  • Service多次绑定同一个service,service的onBind方法只会执行一次,除非Service被终止。当Service的onBind执行后,系统还需要告知客户端已经成功连接Service。由AMS的<code>publishService</code>方法实现。

  • AMS的publishService方法将具体的工作交给了<code>ActivityServices</code>类型的<code>mServices</code>对象来处理.在ActiveServices的<code>publishServiceLocked</code>方法核心代码只有一句

c.conn.connected(r.name, service);
 > c的类型是<code>ConnectionRecore</code>,c.conn的类型是<code>ServiceDispatcher.InnerConnection</code>,service就是Service的onBind方法返回的Binder对象。
  • 从InnerConection的connected方法又调用了<code>ServiceDispatcher</code>的<code>connected</code>方法.

    对于Service的绑定过程来说,<code>ServiceDisptcher</code>的<code>mActivityThread</code>是一个Handler,也就是ActivityThread中的H。
    这样一来<code>RunConnection</code>就可以经过H的post方法从而运行在主线程中,因此客户端<code>ServiceConnection</code>中的方法是在主线程中被回调的。
    <code>RunConnection</code>的run方法简单调用了<code>ServiceDisptcher</code>的<code>doConnected</code>方法,由于<code>ServiceDisptcher</code>内部保存了客户端<code>ServiceConnection</code>对象,因此可以方便调用ServiceConnection对象的<code>onServiceConnected</code>方法。

  • 客户端的<code>onServiceConnected</code>方法执行完毕之后,Service的绑定过程也就分析完成了。

——整理自《Android开发艺术探索》(图片来自网络)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容