![Android进阶解密](https://wfqqreader-1252317822.image.myqcloud.com/cover/331/31186331/b_31186331.jpg)
4.3 Service的绑定过程
我们可以通过调用Context的startService 来启动Service,也可以通过Context的bindService来绑定Service,绑定Service的过程要比启动Service的过程复杂一些,建议阅读本节前先阅读上一节Service的启动过程,结合着Service的启动过程会有更好的理解。关于如何绑定Service这种基础的问题,这里并不会讲解。Service 的绑定过程将分为两个部分来进行讲解,分别是ContextImpl到AMS的调用过程和Service的绑定过程。
4.3.1 ContextImpl到AMS的调用过程
ContextImpl到AMS的调用过程如图4-9所示。
我们可以用bindService方法来绑定Service,它在ContextWrapper中实现,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer53.jpg?sign=1739532805-Sd6v97yhp4nxLXF0z96GMfZ6xRyQ3TME-0-a7da346ba6e700535c4ac230f9ccb233)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer54.jpg?sign=1739532805-1u9dLSnZWp9L11nxhKfO7RhpxB6hO3up-0-4a743ff7a283a43d1fd81bafc2f43f0f)
图4-9 ContextImpl到AMS的调用过程
在4.2.1节我们得知mBase具体就是指向ContextImpl的,接着查看ContextImpl的bindService方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer55.jpg?sign=1739532805-Tq64qRrtWzNpJOFASMB7ecXgkJq1pGuy-0-f985a23aacbb53f02ec284551fca79ae)
在bindService方法中,又返回了bindServiceCommon方法,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer56.jpg?sign=1739532805-JLWvdYRpJlCXzzP62uBC2OmTH0XvWEXd-0-16ecf435762392621565d54324eaece4)
在注释1处调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd,从IServiceConnection的名字我们就能得知它实现了Binder机制,这样Service的绑定就支持了跨进程。接着在注释2处我们又看见了熟悉的代码,最终会调用AMS的bindService方法。
4.3.2 Service的绑定过程
AMS的bindService方法代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer57.jpg?sign=1739532805-5wHo9pfMruGaQuErfnIcBkUwBEQMgVHF-0-eb7905fdc3edb2c7292231168af6ec8b)
bindService方法最后会调用ActiveServices类型的对象mServices的bindServiceLocked方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer58.jpg?sign=1739532805-Wf5BNaKTX4hIhD73mFxjN7vWXjEzdw2G-0-1abaf2fd27b4837f4b3f5f407c9174c8)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer59.jpg?sign=1739532805-pjybdlKKISAVS3vMPb3v57qL9Dgh55am-0-1a37fe0ad17a3de325655b17f24c58db)
讲到这里,有必要先介绍几个与Service相关的对象类型,这样有助于对源码进行理解,如下所示。
· ServiceRecord:用于描述一个Service。
· ProcessRecord:一个进程的信息。
· ConnectionRecord:用于描述应用程序进程和Service建立的一次通信。
· AppBindRecord:应用程序进程通过Intent绑定Service时,会通过AppBindRecord来维护Service与应用程序进程之间的关联。其内部存储了谁绑定的Service (ProcessRecord)、被绑定的Service (AppBindRecord)、绑定Service的Intent (IntentBindRecord)和所有绑定通信记录的信息(ArraySet<ConnectionRecord>)。
· IntentBindRecord:用于描述绑定Service的Intent。
在注释1处调用了ServiceRecord的retrieveAppBindingLocked方法来获得AppBindRecord,retrieveAppBindingLocked 方法内部创建IntentBindRecord,并对IntentBindRecord的成员变量进行赋值,后面我们会详细介绍这个关键的方法。
在注释2处调用bringUpServiceLocked方法,在bringUpServiceLocked方法中又调用realStartServiceLocked 方法,最终由ActivityThread 来调用Service的onCreate 方法启动Service,这也说明了bindService方法内部会启动Service,启动Service这一过程在4.2.2节中已经讲过,这里不再赘述。在注释3处s.app!=null 表示Service 已经运行,其中s 是ServiceRecord类型对象,app是ProcessRecord类型对象。b.intent.received表示当前应用程序进程已经接收到绑定Service 时返回的Binder,这样应用程序进程就可以通过Binder 来获取要绑定的Service的访问接口。在注释4处调用c.conn的connected方法,其中c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,InnerConnection的connected方法内部会调用H的post方法向主线程发送消息,并且解决当前应用程序进程和Service跨进程通信的问题,在后面会详细介绍这一过程。在注释5处如果当前应用程序进程是第一个与Service进行绑定的,并且Service已经调用过onUnBind方法,则需要调用注释6处的代码。在注释7处如果应用程序进程的Client端没有发送过绑定Service的请求,则会调用注释8处的代码,注释8处和注释6处的代码区别就是最后一个参数rebind为false,表示不是重新绑定。接着我们查看注释6处的requestServiceBindingLocked方法,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer60.jpg?sign=1739532805-d4jyYTlHED8Z3N2dc1eQZCSdbvyib943-0-ad75250cbe630891bcef96550274c57f)
注释1处i.requested表示是否发送过绑定Service的请求,从bindServiceLocked方法的注释5处得知是发送过的,因此,!i.requested为false。从bindServiceLocked方法的注释5处得知rebind值为true,那么(!i.requested||rebind)的值为true。i.apps.size()>0表示什么呢?其中i是IntentBindRecord 类型的对象,AMS 会为每个绑定Service的Intent分配一个IntentBindRecord类型对象,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer61.jpg?sign=1739532805-NFWguMiV8SGQYqxrRxcRGV2Qf9fdA13t-0-e5a6b488c61304161934595dd302cc1b)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer62.jpg?sign=1739532805-Jgdjvsuo5SV1SUM3kuZjTiHbOdEaUmUO-0-d6109800d490b3482f81a9a63c44e148)
我们来查看IntentBindRecord 类,不同的应用程序进程可能使用同一个Intent来绑定Service,因此在注释1处会用apps来存储所有用当前Intent绑定Service的应用程序进程。i.apps.size() > 0表示所有用当前Intent绑定Service的应用程序进程个数大于0,下面来验证i.apps.size()>0是否为ture。我们回到bindServiceLocked方法的注释1处,ServiceRecord的retrieveAppBindingLocked方法如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer63.jpg?sign=1739532805-WYrDKAiM4ajGjeemElxlijxc4SlFtVpW-0-c46e78d8be1cf11a274ccb714b0a8db8)
注释1处创建了IntentBindRecord,注释2处根据ProcessRecord获得IntentBindRecord中存储的AppBindRecord,如果AppBindRecord不为null就返回,如果为null就在注释3处创建AppBindRecord,并将ProcessRecord作为key,AppBindRecord作为value保存在IntentBindRecord的apps(i.apps)中。回到requestServiceBindingLocked方法的注释1处,结合ServiceRecord的retrieveAppBindingLocked方法,我们得知i.apps.size()>0为true,这样就会调用注释2处的代码,r.app.thread的类型为IApplicationThread,它的实现我们已经很熟悉了,是ActivityThread的内部类ApplicationThread,scheduleBindService方法如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer64.jpg?sign=1739532805-cb90ZgOpIid5GbLhjBtHQ78jz9sYQuae-0-db94f1af2f5d47fdeb376643c0576c09)
首先将Service的信息封装成BindServiceData对象,BindServiceData的成员变量rebind的值为false,后面会用到它。接着将BindServiceData传入到sendMessage方法中。sendMessage向H发送消息,我们接着查看H的handleMessage方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer65.jpg?sign=1739532805-q2G3nN5V0nR7lFNKdqDU4FR6aKV5mV7L-0-725806fcd1f628a1d5bbe07f7f226c27)
H 在接收到BIND_SERVICE类型消息时,会在handleMessage方法中会调用handleBindService方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer66.jpg?sign=1739532805-jkf6qLkZhD8pXS4MrBO31DSGROpgE2E2-0-3a587c01953e8a4d17af2d4de8f1a74a)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer67.jpg?sign=1739532805-eeVyAYClGPGazUcTJmeIer1alohRK6pQ-0-3827b4bfbe4535fd18f995ac27977d69)
在注释1处获取要绑定的Service。注释2处的BindServiceData的成员变量rebind的值为false,这样会调用注释3处的代码来调用Service的onBind方法,到这里Service处于绑定状态了。如果rebind的值为true就会调用注释5处的Service的onRebind方法,这一点结合前文的bindServiceLocked方法的注释5处,得出的结论就是:如果当前应用程序进程第一个与Service进行绑定,并且Service已经调用过onUnBind方法,则会调用Service的onRebind方法。handleBindService方法有两个分支,一个是绑定过Servive的情况,另一个是未绑定的情况,这里分析未绑定的情况,查看注释4处的代码,实际上是调用AMS的publishService方法。讲到这里,先给出这一部分的代码时序图(不包括Service启动过程),如图4-10所示。
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer70.jpg?sign=1739532805-r1bmAtJal9QBawj9BfD4oXYdfe5nqmSl-0-9b79bbca2f05d4001d2d6f465ce5c2c6)
图4-10 Service的绑定过程前半部分调用关系时序图
接着来查看AMS的publishService方法,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer68.jpg?sign=1739532805-mGGziO9NZkFfSJy5bdGiEMEyQaGqK5sQ-0-ad4706d963239feea0633a950bbcb3d1)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer69.jpg?sign=1739532805-36lgjernUHu2NE5MYIoYsVYIe9hCg5QF-0-bbe9dfc0a667b1960feab59005d5ebbc)
在publishService方法中调用了ActiveServices类型的mServices对象的publishServiceLocked方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer71.jpg?sign=1739532805-HH3AtltHJUlqWzs7WsIXKPj3VCh08Qpa-0-4fc3ecc5831af686892b4875494fc838)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer72.jpg?sign=1739532805-Z5qnD2dVssMl4Aj1pbHPKxca2bglRWc0-0-a16021c10e28faffcd2dada2e0bec68c)
注释1处的代码在前面介绍过,c.conn指的是IServiceConnection,它是ServiceConnection在本地的代理,用于解决当前应用程序进程和Service跨进程通信的问题,具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,ServiceDispatcher.InnerConnection的connected方法的代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer73.jpg?sign=1739532805-oBl0G9LmKOLE9ZCLnMLZsVCHPmh2h74m-0-03c81a04e8f86ea9758a79eede579286)
在注释1处调用了ServiceDispatcher类型的sd对象的connected方法,代码如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer74.jpg?sign=1739532805-CjHBCHQSb0JPDUSg1DI0G8y5Wr0cTg3P-0-3a96c1ef5a2c69f8dd2f6270f2b8a64c)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer75.jpg?sign=1739532805-fOVMPhjKiNZWtftAeQQWQXi6HJSQYkrn-0-2955841b7b395f5d68c1a570188bd96e)
在注释1处调用Handler类型的对象mActivityThread的post方法,mActivityThread实际上指向的是H。因此,通过调用H的post方法将RunConnection对象的内容运行在主线程中。RunConnection是LoadedApk的内部类,定义如下所示:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer76.jpg?sign=1739532805-cnbdaUNK3vPA3fxPZSaXid54iNIGXQZp-0-b8a30c8f91850c0397fe74315ff04806)
在RunConnection的run方法中调用了doConnected方法:
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer77.jpg?sign=1739532805-S7wXXdIpRabgmDFJcHOmo56kIOB93UJE-0-0df9e223c8056affd328e4988bc2f2d0)
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer78.jpg?sign=1739532805-SFGVCrcLkc5wJWEdNBY0BoIyaKPezwVO-0-38bcd0b7e7f3b7e1f3f2a09302232f74)
在注释1处调用了ServiceConnection 类型的对象mConnection 的onServiceConnected方法,这样在客户端实现了ServiceConnection接口类的onServiceConnected方法就会被执行。至此,Service 的绑定过程就分析完成。最后给出剩余部分的代码时序图,如图4-11所示。
![](https://epubservercos.yuewen.com/D63A94/16896237205618706/epubprivate/OEBPS/Images/figer79.jpg?sign=1739532805-mShTdRwF2QYLo29fZ1D0xDnDDBz4MZ1I-0-4b96e8b31b4b372a3bdeb777a99a5a7f)
图4-11 Service的绑定过程剩余部分的代码时序图