Binder、AIDL和IPC

作者: LeeIA_e9f6 | 来源:发表于2017-07-30 11:24 被阅读0次

    绑定本地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

        本文链接:https://www.haomeiwen.com/subject/kcbhlxtx.html