Android进程通信Binder(1)-Binder进程通信的思想

在android中Binder用于完成进程间通信,Binder工作在Linux层,属于一个驱动,只是这个驱动不需要硬件,其操作的硬件基于某一小端内存。从线程的角度来讲,Binder驱动代码运行在内核态,客户端程序调用Binder是通过系统调用完成的。

Binder是一种架构,这种架构提供了服务端接口、Binder驱动、客户端接口三个模块。
服务端:一个服务端实际上就是一个Binder类的对象,这个对象一旦创建,就会启动一个隐藏线程。该线程用来接收Binder驱动发送的消息,接收到消息后,会执行到Binder对象中的onTransact()方法。因此Binder服务的实现要重载onTransact()方法。
Binder驱动:任意一个服务端Binder对象创建时,同时会再Binder驱动中创建一个mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务,都通过mRemote对象进行访问。
客户端:客户端要想访问远程服务,必须获取远程服务的Binder对象中的对应的mRemote引用,通过调用mRemote的transact()方法,访问远程服务。

在Binder驱动中,mRemote对象也重载了transact()方法,重载的主要内容如下:
  • 以线程通信的方式,向服务端发送客户端传递过来的参数
  • 挂起当前线程(客户端线程),并等待服务器端线程执行完指定任务后的通知
  • 接收服务端线程通知,然后执行客户端线程,并返回到客户端代码区
从上面可以看出,客户端程序似乎只直接调用了远程服务对应的Binder,而实际上则是通过Binder 驱动进行了中转。实际上是存在两个Binder对象,一个是服务端的Binder对象,一个是驱动中的Binder对象,驱动中的Binder对象不会额外产生一个线程,直接就是客户端程序的线程。

关于Binder的设计

设计Service端:只需要实现Binder类,然后重写Binder的protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) ;
然后根据code执行部同的操作,从data中读取客户端传过来的数据,这里需要注意一下data传过来参数的顺序,得和客户端有个约定才行。
执行完操作之后,把reply存上数据,返回给客户端

设计客户端:首先是获取服务端在Binder驱动中对应的mRemote变量的引用,就可以调用mRemote的transact()方法了。

对于以上的设计,需要解决的两个问题是:
  1. 客户端如何获得服务端的Binder对象引用
  2. 客户端和服务端如何约定参数在Parcel中的传递顺序和服务端如何知道调用什么服务的函数。
对于第一个问题而言,如果可以方便应用程序开发者的话,系统应该把这个功能给提供出来,android系统确实是这么做的,通过
Service可以提供Binder的引用。第二个问题程序员既可以自行实现,也可以使用aidl工具进行默认实现

获得服务端的Binder对象引用

在Activity中可以使用startService()启动一个服务,这个实现在android.app.ContextImpl类中实现的,
在这里的时候只是把服务开启了,还是没有服务端的Binder的引用的。
public boolean bindService(Intent service, ServiceConnection conn,
            int flags) 这个方法才能真正的返回服务端的binder引用。
不过需要实现ServiceConnection 接口,接口定义如下:

public interface ServiceConnection {
 
    public void onServiceConnected(ComponentName name, IBinder service);
    
    public void onServiceDisconnected(ComponentName name);

}
当Service能正常启动,然后系统会为远程的服务Binder的引用,onServiceConnected(ComponentName name, IBinder service)里的
service就是那个服务端的Binder引用。

客户端和服务端的参数传递
关于客户端和服务端的参数传递,androidSDK中提供了一个aidl的工具,这个工具可以把aidl文件转化为java文件,并且重载了transact()
和onTransact()方法,统一了存入包裹和读取包裹的参数,程序员只需关注业务代码实现即可。

aidl的具体使用其实很简单,就是把一个借口文件的修饰符删除,把文件名修改成以.aidl结尾的文件即可,如下::

关于具体的规则,自行去官方文档查看。
下面主要分析aidl工具生成的java类
第7行 定义了一个IMusicService接口,并继承了android.os.IInterface接口,这个接口有一个方法定义asBinder(),这个asBinder接口就
    是用来返回Binder对象的。
第9行 定义了一个抽象内部类Stub,这个内部类继承了android.os.Binder并实现了com.suchangli.binderdemo.IMusicService。
    这里重点解释一下,为什么要设计成抽象类,这个抽象类主要是给服务端用的,服务端继承这个Stub类,去实现具体的业务代码。
    并且重载了transact()和onTransact()方法,包裹数据的存入顺序已经由aidl定义好。
第59行 定义了一个Proxy类,该类将作为客户端访问服务端的代理。
第94行 TRANSACTION_start常量,这个常量就是onTransact()中的第一个参数,用来标示执行什么服务动作的。
第22-32行 这个是实现的asInterface()方法,这个方法的作用是返回一个Binder对象,当然,这里返回的是 com.suchangli.binderdemo.IMusicService对象。看看里面的实现很有意思,调用这个方法的客户端,如果是本地的客户端,
不许要跨进程调用,那么直接在进程内部调用就可以了,只有事远程的客户端才会返回一个Binder代理。这个asInterface()提供了一个
通用的访问接口,不管是本地调用还是远程的调用,都会返回一个Binder对象,这个对象有可能就是直接实现的Stub实例或者是Proxy的实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值