[Framework] Android Binder 工作原理
Binder 是 Android 体系中主要的 IPC 通讯办法,其功能十分优异。可是包含我在内的很多开发者都对它望而生畏,确实比较难,每次都是看了忘,忘了看,可是随着工作的时间约来越长,每次看也都对 Binder 有新的认识,所以这次把自己的一些认识记录一下。
从 Framework/Driver 来看 Binder
![[Framework] Android Binder 工作原理 [Framework] Android Binder 工作原理](https://www.6hu.cc/wp-content/uploads/2023/10/1696289636-8a45201bf997526.webp)
Binder 设计是经典的 C/S 架构,Client 向 Server 主动恳求,Server 收到音讯后回复,一个 Server 可以服务多个 Client,Server 不能主意向 Client 发送音讯。
所有的进程发动都会通过 bind_open 翻开 binder 驱动,通过 mmap 完结内存映射,不同的进程在翻开驱动后,binder 驱动会为其创立一个 binder_proc 节点来表明该进程,当该进程有新的 Server 时,就会在 binder_proc 中增加一个 binder_node 来表明这个服务,当该进程想要向其他进程的 Server 通讯时,在 binder_proc 中增加一个 binder_ref (其间包含 handle, 这个值是在同一个进程中顺次增加,不同进程中的同一服务的handle 也是不相同的, ServiceManager 的 handle 是个破例,它固定为 0) 来描绘对方针 Server 的引证,binder_proc, binder_node 和 binder_ref 他们都是以链表的形式存储。
ServiceManager
Server 的管理是通过 ServiceManager 的,他自己也是一个 binder 的 Server,其他服务假如要增加,需求通过它的 addService 办法,假如要获取需求通过它的 getService 办法,咱们也针对这两个办法剖析。
当一个进程想要将注册 Server 时,会通过 binder IPC 通讯的办法调用 ServiceManager 的 addService 办法,参数中也会包含 Server,这个 Server 会先抵达 binder 驱动,驱动会去检查这个进程中是不是有这个服务对应的 binder_node,由于是第一次,这个服务是没有的,然后驱动会在对应的 binder_proc 上创立一个 binder_node 来表明这个服务, binder 驱动需求把这个 Server 告诉给 ServiceManager 地点的进程,可是不能直接用对应的 binder_node, 而需求在 ServiceManager 对应的 binder_proc 上增加一个 binder_ref 来指向那个 Binder Server,而 binder_ref(包含 handle) 就可以回来给 ServiceManager 对应的进程,ServiceManager 进程中会记录这个 Server 的姓名和 handle 等信息。这就完结了一个服务的增加。
当一个进程想要与某个 Server 通讯时,会通过 binder IPC 通讯的办法调用 ServiceManager 的 getService 办法,这个办法的参数中包含这个服务的姓名(字符串),这个恳求通过 binder IPC 抵达 ServiceManager 地点的进程后,会通过这个姓名去查找对应的 Server, 找到了这个服务就会把这个服务的通过 binder IPC 回复给方针进程,前面说过 ServieManager 进程中保存的仅仅一个 binder_ref (handle) 引证,当 binder 驱动收到这个回复后,会去通过这个引证获取 Server 对应的 binder_node,驱动会去比较发送进程和接纳进程,在 ServiceManager 回复的这个逻辑中,发送进程是 ServiceManager,接纳进程是获取这个服务的进程,他们肯定不相同,前面也说到,就算同一个 Server 的 binder_ref 在不同的进程中也是不相同的,所以 ServiceManager 进程中的 binder_ref 不能直接给获取这个服务的进程运用,就需求给获取服务的这个进程再创立一个 binder_ref,一起这个 binder_ref 也是指向方针 Server 的 binder_node,然后把这个 binder_ref (handle) 回来给恳求服务的进程就好了,后续和 Server 的通讯也都全部仰仗这个 binder_ref(handle) 了。
前面说到 ServiceManager 也是一个 binder 的 Server,无论是增加 Server 仍是获取 Server 都要通过它,咱们的进程要与 ServiceManager 通讯必须要对应的 handle,可是咱们要怎样获取这个 handle 呢?这儿 binder 留了一个后门,ServcieManager 的 handle 对所有的进程都相同,都是 0,所以不用获取,直接用就好了。
Binder 高速的隐秘
在上面说到进程发动时会调用 binder 的 bind_open 和 mmap 办法,其间 mmap 流程便是速度快的原因。通过 mmap 在通讯的进程中只会有一次用户空间和内核空间的数据拷贝,其他的 IPC 通讯办法大多都有 2 次或者更多。
在 mmap 中 binder 会为进程分配一块物理内存,binder 和 Server 的虚拟内存都会指向这块内存,也便是这块物理内存是他们共用的。当 Client 发送音讯给 Server 时,Binder 会将 Client 发送过来的音讯拷贝到 mmap 分配的内存中,然后 binder 告诉 Server 去运用,Server 处理完结后把回复的音讯也写入这块内存,告诉 binder 回复 Client,binder 将回复的音讯再拷贝到 Client 地点的进程,回复 Client 完结调用。这块内存空间的最大值为 1MB - 8KB。
![[Framework] Android Binder 工作原理 [Framework] Android Binder 工作原理](https://www.6hu.cc/wp-content/uploads/2023/10/1696289642-371c3a5eeb2367a.webp)
Binder IPC 通讯进程
通讯进程中需求有一些协议,这儿来描绘一下不同的协议,协议通常分为操控协议和驱动协议。
操控协议是其他进程通过 ioctl(“/dev/binder”) 办法向驱动发送指令,其间包含以下几种:
| 指令 | 阐明 | 参数类型 |
|---|---|---|
| BINDER_WRITE_READ | 读写操作,最常用的指令。IPC进程便是通过这个指令进行数据传递 | binder_write_read |
| BINDER_SET_MAX_THREADS | 设置进程支撑的最大线程数量 | size_t |
| BINDER_SET_CONTEXT_MGR | 设置自身为ServiceManager | 无 |
| BINDER_THREAD_EXIT | 告诉驱动Binder线程退出 | 无 |
| BINDER_VERSION | 获取Binder驱动的版本号 | binder_version |
驱动协议包含以下两种进程发送给驱动的协议(binder_driver_command_protocol)和驱动发送给进程的协议(binder_driver_return_protocol)。
binder_driver_command_protocol:
| 指令 | 阐明 | 参数类型 |
|---|---|---|
| BC_TRANSACTION | Binder业务,即:Client关于Server的恳求 | binder_transaction_data |
| BC_REPLY | 业务的应对,即:Server关于Client的回复 | binder_transaction_data |
| BC_FREE_BUFFER | 告诉驱动开释Buffer | binder_uintptr_t |
| BC_ACQUIRE | 强引证计数+1 | __u32 |
| BC_RELEASE | 强引证计数-1 | __u32 |
| BC_INCREFS | 弱引证计数+1 | __u32 |
| BC_DECREFS | 弱引证计数-1 | __u32 |
| BC_ACQUIRE_DONE | BR_ACQUIRE的回复 | binder_ptr_cookie |
| BC_INCREFS_DONE | BR_INCREFS的回复 | binder_ptr_cookie |
| BC_ENTER_LOOPER | 告诉驱动主线程ready | void |
| BC_REGISTER_LOOPER | 告诉驱动子线程ready | void |
| BC_EXIT_LOOPER | 告诉驱动线程现已退出 | void |
| BC_REQUEST_DEATH_NOTIFICATION | 恳求接纳逝世告诉 | binder_handle_cookie |
| BC_CLEAR_DEATH_NOTIFICATION | 去除接纳逝世告诉 | binder_handle_cookie |
| BC_DEAD_BINDER_DONE | 现已处理完逝世告诉 | binder_uintptr_t |
binder_driver_return_protocol:
| 回来类型 | 阐明 | 参数类型 |
|---|---|---|
| BR_OK | 操作完结 | void |
| BR_NOOP | 操作完结 | void |
| BR_ERROR | 产生过错 | __s32 |
| BR_TRANSACTION | 告诉进程收到一次Binder恳求(Server端) | binder_transaction_data |
| BR_REPLY | 告诉进程收到Binder恳求的回复(Client) | binder_transaction_data |
| BR_TRANSACTION_COMPLETE | 驱动关于接受恳求的确认回复 | void |
| BR_FAILED_REPLY | 奉告发送方通讯方针不存在 | void |
| BR_SPAWN_LOOPER | 告诉Binder进程创立一个新的线程 | void |
| BR_ACQUIRE | 强引证计数+1恳求 | binder_ptr_cookie |
| BR_RELEASE | 强引证计数-1恳求 | binder_ptr_cookie |
| BR_INCREFS | 弱引证计数+1恳求 | binder_ptr_cookie |
| BR_DECREFS | 弱引证计数-1恳求 | binder_ptr_cookie |
| BR_DEAD_BINDER | 发送逝世告诉 | binder_uintptr_t |
| BR_CLEAR_DEATH_NOTIFICATION_DONE | 整理逝世告诉完结 | binder_uintptr_t |
| BR_DEAD_REPLY | 奉告发送方对方现已逝世 | void |
在上面介绍了一些指令后,你可能仍是不怎样清楚详细怎样通讯的,我这儿描绘一次简略的 binder IPC 通讯:
Client 通过 ServiceManager 获取到方针 Server 的 handle 后,底层调用 ioctl 办法,对应的 ioctl 指令是 BINDER_WRITE_READ,其间还传递了发送给服务端的包裹的数据,也包含了 binder 驱动指令, 这个指令是 BC_TRANSACTION,binder 驱动收到后会向 Client 线程回复 BR_TRANSACTION_COMPLETE 表明现已收到恳求,binder 驱动会将 Client 传递过来的数据拷贝到对应 Server 的 mmap 内存空间,然后向 Server 发送 BR_TRANSACTION 指令,表明有新的 Client 恳求,Server 会读取对应存在 mmap 中的 Client 恳求数据,然后解析恳求内容,Server 完结恳求后,会把回来的数据封装在 reply 中,然后相同通过 ioctl 的 BINDER_WRITE_READ 指令封装回复的数据和驱动指令,驱动指令是 BC_REPLY,binder 驱动收到后会向 Server 发送 BR_TRANSACTION_COMPLETE 指令,表明现已收到给 Client 的回复,在 binder 驱动中会将 Server 的回复数据拷贝到 Client 地点的进程,然后向 Client 发送 BR_REPLY 表明恳求成功,Client 最终解分出 Server 发送来的数据,这样就完结了一次恳求。
在 Android 中 Client 和 Server 目标的命名通常有有以下规律:
| – | C/C++ | Java | AIDL |
|---|---|---|---|
| Server | BnXXX | XXXNative | IXXX.Stub |
| Client | BpXXX | XXXProxy | IXXX.Stub.Proxy |
从 Service 和 AIDL 来看 binder
Android 中官方供给的仅有运用 binder 的接口便是运用四大组件之一的 Service 了,在 onBind() 回调中回来 Binder 的 Server,客户端发动 Service 的办法修改成 bindService(),其间 Service 中的 Binder 的 Server 准备就绪后会传给发动进程的 Connection 回调,当然发动进程收到的 IBinder 目标仅仅一个署理而已。
Android 为了让开发者可以更容易地运用 binder,创造了 AIDL 这言语,应用在编译时,编译器会把咱们声明的 AIDL 文件编译成 Java 源码文件,通过生成的源码文件咱们可以像在调用本地办法代码相同调用其他进程的 Server,当然实际上是运用的 binder IPC。有人说 AIDL 是一种 IPC 的通讯办法,我反正感觉怪怪的,它仅仅简化了 binder 的运用,而不是一种通讯办法,binder 才是它的通讯办法。
AIDL
这儿简略描绘一下 AIDL 特其他关键字:
-
oneway
符号到办法中,表明这个办法只需求发送数据给Server,而不需求Server的回复(前面说到Client发送数据给Server后,需求等候Server再回来数据给Client,这仅仅一般状况。);通常这样的话办法的调用耗时就更短,有人把这个说成是异步调用,合理地运用oneway可以进步程序的功能. -
in
符号到办法参数中,表明这个参数仅仅当输入发送给Server,当服务端修改这个目标里面的参数后不会同步到Client。 -
out
符号到办法参数中,表明这个参数仅仅当输出发送给Server,Server会把回来成果写入到这个目标的参数里,写入后会同步到Client。 -
inout
符号到办法参数中,也便是一起满足in和out的特点。
后续我就通过一个 AIDL 例子来介绍一下。
这是我的 AIDL 文件:
interface IPlayingMusicService {
PlayingMusicModel getPlayingMusicModel();
void pause();
void stop();
void start();
void addProgressCallback(MusicPlayingCallback callback);
void removeProgressCallback(long callbackId);
void newPlayingMusicModel(PlayingMusicModel newMusic);
}
除了 Java 中的 8 种基本类型、String 和 Binder 以外,其他的运用到的目标都要完成 Parcelable 接口,这也很好了解,跨进程传输数据肯定需求序列化和反序列化了。
用到的目标需求用 AIDL 文件描绘下:
package com.example.aidldemo;
parcelable PlayingMusicModel;
总的来说 AIDL 便是界说了一堆服务的接口,咱们来看看它生成的 Java 源码:
public interface IPlayingMusicService extends android.os.IInterface
{
// ...
public static abstract class Stub extends android.os.Binder implements com.example.aidldemo.IPlayingMusicService
{
private static final java.lang.String DESCRIPTOR = "com.example.aidldemo.IPlayingMusicService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.aidldemo.IPlayingMusicService interface,
* generating a proxy if needed.
*/
public static com.example.aidldemo.IPlayingMusicService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidldemo.IPlayingMusicService))) {
return ((com.example.aidldemo.IPlayingMusicService)iin);
}
return new com.example.aidldemo.IPlayingMusicService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
// ..
}
private static class Proxy implements com.example.aidldemo.IPlayingMusicService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public com.example.aidldemo.PlayingMusicModel getPlayingMusicModel() throws android.os.RemoteException
{
// ...
}
@Override public void pause() throws android.os.RemoteException
{
// ...
}
@Override public void stop() throws android.os.RemoteException
{
// ...
}
@Override public void start() throws android.os.RemoteException
{
// ...
}
@Override public void addProgressCallback(com.example.aidldemo.MusicPlayingCallback callback) throws android.os.RemoteException
{
// ...
}
@Override public void removeProgressCallback(long callbackId) throws android.os.RemoteException
{
// ...
}
@Override public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException
{
// ...
}
public static com.example.aidldemo.IPlayingMusicService sDefaultImpl;
}
static final int TRANSACTION_getPlayingMusicModel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_addProgressCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_removeProgressCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
static final int TRANSACTION_newPlayingMusicModel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
public static boolean setDefaultImpl(com.example.aidldemo.IPlayingMusicService impl) {
// Only one user of this interface can use this function
// at a time. This is a heuristic to detect if two different
// users in the same process use this function.
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.example.aidldemo.IPlayingMusicService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public com.example.aidldemo.PlayingMusicModel getPlayingMusicModel() throws android.os.RemoteException;
public void pause() throws android.os.RemoteException;
public void stop() throws android.os.RemoteException;
public void start() throws android.os.RemoteException;
public void addProgressCallback(com.example.aidldemo.MusicPlayingCallback callback) throws android.os.RemoteException;
public void removeProgressCallback(long callbackId) throws android.os.RemoteException;
public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException;
}
IPlayingMusicService 是一个接口,也便是咱们在 AIDL 中界说的那些办法,除此之外其间的静态类 Stub 和 Stub.Proxy 他们占有了大部分的篇幅,Stub 其实便是表明 binder 的 Server,Stub.Proxy 便是 binder 的 Client,他们也都增加了 IPlayingMusicService 接口,Stub.Proxy 是个一般类,现已把接口完成好了,Stub 是一个抽象类 IplayingMusicService 的接口需求咱们自己完成,这也很好了解,Server 的这些办法当然需求咱们自己去界说了,Client 当然不用在界说了,因为它最终便是会调用 Server 中的这些办法。
咱们自己的 Server 完成就相似以下代码:
val binder: IBinder = object : IPlayingMusicService.Stub() {
override fun pause() {
// TODO:
}
override fun newPlayingMusicModel(newMusic: PlayingMusicModel) {
// TODO:
}
override fun start() {
// TODO:
}
override fun stop() {
// TODO:
}
override fun getPlayingMusicModel(): PlayingMusicModel? {
// TODO:
}
override fun addProgressCallback(callback: MusicPlayingCallback?) {
// TODO:
}
override fun removeProgressCallback(callbackId: Long) {
// TODO:
}
}
然后咱们需求把这个目标在四大组建之一的 Service 的 onBind 回调中回来给体系:
// ...
override fun onBind(intent: Intent?): IBinder = binder
// ...
这个 Server 会通过 binder 转到 AMS,然后通过 AMS 再通过 binder 传递到发动的进程。
也便是回到以下回调:
bindService(
Intent(this@MainActivity, MusicPlayingService::class.java),
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val binderProxy = IPlayingMusicService.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
}
},
Context.BIND_AUTO_CREATE
)
回调中的 IBinder 目标是其一个署理目标,也便是前面说到的 handler 封装过的目标。咱们会运用 IPlayingMusicService.Stub.asInterface 办法把 IBinder 目标封装成具有 IPlyaingMusicService 接口的目标。咱们去看看这个办法的完成:
public static com.example.aidldemo.IPlayingMusicService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.aidldemo.IPlayingMusicService))) {
return ((com.example.aidldemo.IPlayingMusicService)iin);
}
return new com.example.aidldemo.IPlayingMusicService.Stub.Proxy(obj);
}
这儿很重要他首要会调用 IBinder 的 queryLocalInterface 办法去查询一下这个服务是否在当前进程中,假如不为空便是表明在当前进程中,然后会直接运用,其实这个目标便是 onBind() 中的那个 Server 目标,也便是 Stub 目标,也便是说直接拿那个目标调用办法,也就没有通过 binder 进行 IPC 通讯,就和一般的目标调用没有差异;可是假如 queryLocalInterface 办法回来为空,表明这个 Server 是其他进程中的,这时会生成一个 Stub.Proxy 目标,通过这个目标的办法调用便是通过 binder IPC 完成的。
咱们看看 Stub.Proxy 目标中的 newPlayingMusicModel 办法完成(其他办法也迥然不同):
@Override public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((newMusic!=null)) {
_data.writeInt(1);
newMusic.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
boolean _status = mRemote.transact(Stub.TRANSACTION_newPlayingMusicModel, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().newPlayingMusicModel(newMusic);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
运用的是 Parcel 来传输数据,首要写入一个 Token 来表明这个恳求,我这儿的 demo 便是 com.example.aidldemo.IPlayingMusicService,然后在把参数写入,然后调用 mRemote (这个便是 bindServer 传过来的 IBinder 目标) 的 transact 办法来发送数据,这儿还通过 TRANSACTION_newPlayingMusicModel 符号了要恳求的办法,Server 回复的数据放在 _reply 中,这个 transact 办法最终也会走到上面说过的 ioctl 办法,指令是 BINDER_WRITE_READ,由于上面现已描绘过了,就不再多说,等候 Server 回复后检查是否有反常,然后解析回来成果。(我的这个办法回来为 void,所以不用解析)
咱们持续来看服务端 Stub 是怎样来处理这个 Stub.Proxy 发送过来的音讯的,处理的入口函数是 onTransact 办法:
// ...
case TRANSACTION_newPlayingMusicModel:
{
data.enforceInterface(descriptor);
com.example.aidldemo.PlayingMusicModel _arg0;
if ((0!=data.readInt())) {
_arg0 = com.example.aidldemo.PlayingMusicModel.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.newPlayingMusicModel(_arg0);
reply.writeNoException();
return true;
}
// ...
首要依据 Code 来判别调用的哪个办法,然后校验 Token,持续解析 Stub.Proxy 传递过来的参数,最终调用咱们自己完成的 newPlayingMusicModel 办法,再将回来成果写入到 reply 中(咱们这个办法没有回来值)。
到此咱们就跑通了整个 AIDL 通讯的流程。
AIDL Demo
Binder 目标在 Framework 中怎么传递到调用方
咱们的 Service#onBind 回调目标 Binder 会在 ActivityThread 的 handBindService 办法中被调用:
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (Exception e) {
...
}
}
}
咱们看到把咱们的 binder 传递给 ActivityManagerNative 的 publishService 办法,其实 ActivityManagerNative 也是一个 binder 署理,而这个 Server 也便是大名鼎鼎的 ActivityManagerService (AMS), 后续的处理也就到了体系进程。
public void publishService(IBinder token, Intent intent, IBinder service) {
...
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (r != null) {
Intent.FilterComparison filter = new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
continue;
}
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
...
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
咱们看到调用了 Connection 的 connected 办法,其实这个 conn 也是一个 binder 的署理,真正的 Server 完成是调用的 bindService 的进程,也就由 AMS 又传递到了调用的进程。完成 conn 的 Server 代码:
private static class InnerConnection extends IServiceConnection.Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected(ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
sd.connected(name, service);
}
}
}
最终调用到咱们的回调:
public void doConnected(ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this) {
if (mForgotten) {
return;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return;
}
if (service != null) {
mDied = false;
info = new ConnectionInfo();
info.binder = service;
//创立逝世监听目标
info.deathMonitor = new DeathMonitor(name, service);
try {
//树立逝世告诉
service.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return;
}
} else {
mActiveConnections.remove(name);
}
if (old != null) {
old.binder.unlinkToDeath(old.deathMonitor, 0);
}
}
if (old != null) {
mConnection.onServiceDisconnected(name);
}
if (service != null) {
//回调用户界说的ServiceConnection()
mConnection.onServiceConnected(name, service);
}
}
所以这个 Binder 由服务地点的进程 -> AMS -> 调用地点的进程,这个进程中没有通过 ServiceManager 进行注册哦。
参考文章
Binder系列5—注册服务(addService)
Binder系列6—获取服务(getService)
bindService发动进程剖析
了解Android Binder机制(1/3):驱动篇
