Binder、AIDL和IPC

绑定本地service并通讯

在service中定义Binder类,Binder类方法中可以访问service的信息,在service的onbind返回binder类。

activity在它的serviceconnection.onserviceconected方法中会获得onbind返回的binder对象,从而访问service信息。

所以对本地service来说,binder对象就是service返回的代理对象,客户端可以通过它反问service内部数据,从而实现客户端和service之间的通讯。

如果我们有一个接口提供服务,接口一定是抽象的,可以在service中创建实现接口的binder类,达到服务的目的,剩下的和上面的相同,返回这个binder类为客户端提供服务。

如果service想进行高消耗行为,可以继承intentservice方法,可以进行串联耗时工作,但不支持并发。

并发需要添加handle

onStartCommand返回值

如果service不在同一线程需要AIDL

首先将接口AIDL化,AIDL会自动生成java文件。

之后服务端修改binder类继承AIDL.stub,它是继承了binder类并且实现了AIDL接口。

客户端通过AIDL.Stub.asInterface(service)获得binder。

binder和service,IPC之间关系

service通信采用Ibinder通信,Ibinder也主要用于service,包含两种,一种是本地通信,另一种是多进程通信,也就是IPC。

实现Ibinder可以3种方法,继承Binder类,多进程通信可以采用AIDL和Messanger

其实AIDL也是继承Binder类。

Messenger核心,Message以及Handler。

首先服务端创建一个Handler,里面有handleMessage处理客户端

之后使用回调的Handler创建一个Messenger,Messenger(Handler){Handle.getIMessenger()}

在onbind方法中返回底层的binder Messenger.getBinder().

客户端的onServiceConnected通过传过去的Ibinder创建Messenger(Ibinder){IMessenger.Stub.asInterface(Ibinder)},之后通过Messenger传递Message。

使用的载体what,arg1,arg2,Bundle以及replyTo

如果需要服务端对客户端进行回复,客户端定义一个reHandler,利用这个Handler创建一个reMessenger,设置msg.replyto=reMessenger指定回复接收消息者,之后通过seMessenger发送信息,seMessenger收到信息,seHandle处理,通过reMessenger.send 发送

可以看出Messenger就是一个收件地址

AIDL步骤

服务端创建AIDL文件包含接口,在service中实现这些接口

客户端绑定服务端,将onServiceConnection得到的Ibinder转化为AIDL生成的Iinterface实例,通过实例调用方法。

Messenger和AIDL

Messenger串联AIDL并发

service生命周期

onUnbind返回true调用onRebind,onRebind返回空值,但可以接收Ibinder

false调用onBind

AIDL流程

AIDL创建以后客户端服务端都要有

创建的接口继承了IInterface

服务端

- 重写AIDL.Stub中的方法,具体实现BookManager.stub mBookManager = new BookManager.stub() 并在内部实现具体方法。也可以服务端新建继承Stub类

- onBind中返回AIDL.Stub

客户端

AIDL.Stub.asInterface(service)获得binder。

AIDL源码分析

客户端分析

asInterface传参Ibinder返回stub

先判定是否在同一进程,如果是,返回服务端AIDL的interface对象本身,就是Stub,否则返回Stub.proxy

proxy获取换过去的Ibinder mremote

- 生成_data _reply数据流data.writeInterfaceToken(DESCRIPOR)

- 调用mremote.transact传给服务端并请求服务端调用指定方法。调用的是Stub中的实现方法。

- 接收reply数据流

服务端分析

1获取客户端传过来数据,根据ID执行响应操作

2传过来数据data取出来,调用本地方法。data.enforceInterface(DESCRIPTOP)

3回传数据写入reply

服务端调用客户端方法

提供一个AIDL的客户端方法的接口,因为AIDL中无法使用普通接口

在客户端中对方法进行具体实现

Binder连接池

- 为连接池创建queryBinder接口

- 为连接池创建远程service,并实现queryBinder,返回需要具体的继承Stub的Binder对象

使用

- 连接service,获取Binderpoor

- 获得连接池

- 通过queryBinder获取Binder

注意事项

- onTransact返回false,客户端的请求会失效。

- 客户端线程会被挂起直至服务端进程返回数据,所以耗时方法不应在UI线程执行。

- 服务端的Binder 方法在Binder线程池中,所以应采用同步方式。

- Binder意外死亡,需要重新连接服务,两种方法,第一种给Binder设置死亡代理,linkToDeath(DeathRecipient{binderDied{unlinkToDeath}})设置死亡代理,死亡会回调客户端Binder线程池中binderDied方法。第二种方法,在onServiceDisconnected重连,在客户端中UI线程中被回调。另外可以设置isBinderAlive检查Binder是否死亡

- CopyOnWriteArrayList支持并发读写

- RemoteCallbackList 系统专门提供用于删除跨进程listener接口 使用原因 多次跨进程传输客户端的同一个对象会在服务端生成不同对象,但新生成对象底层Binder对象是同一个

- 客户端调用远程服务的方法,被调用的方法运行在服务端的Binder线程池中,Binder线程池可以执行大量耗时工作,如果某个远程方法是耗时的,避免在UI线程中调用。远程服务端调用客户端中方法,被调用方法运行在客户端Binder线程池中,不能访问UI内容,如果要访问客户端UI,需要使用Handler切换到UI线程

- 在AIDL中使用权限验证功能,1在onBind中进行验证,使用permission,返回null2在服务端onTransact方法中返回false,可以通过permission或UidPid验证

IPC方式

1使用Bundle,只能放入序列化数据

2使用文件共享,避免数据同步,妥善处理并发读写。不建议SharedPreferences,缓存在内存中,多进程模式下读写不可靠,会丢失数据。

3Messenger

4AIDL

5ContentProvider

底层Binder

通过ContentProvider跨进程通信

- ContentProvider六个方法,onCreat运行在主线程,其他getTypeCRUD运行在Binder线程池中,每次的线程都不一样

4Socket

流势套接字Tcp 用户数据报套接字UDP

你可能感兴趣的:(Binder、AIDL和IPC)