5.Binder

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

Binder是一种架构,这种架构提供了服务端接口、Binder驱动、客户端接口三个模块。 首先来看服务端。一个Binder服务端实际上就是一个Binder类的对象,该对象一旦创建,内部就启动一个隐藏线程。该线程接下来会接收Binder驱动发送的消息,收到消息后,会执行到Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务代码。因此,要实现一个Binder服务,就必须重载onTransact()方法。可以想象,重载onTransact()函数的主要内容是把onTransact()函数的参数转换成服务函数的参数,而onTransact()函数的参数来源是客户端调用transact()函数时输入的,因此,如果transact()有固定格式的输入,那么onTransact()就会有固定格式的输出。 下面再看Binder驱动,任意一个服务端Binder对象被创建时,同时会在Binder驱动中创建一个mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务时,都是通过mRemote对象。 最后来看应用程序客户端,客户端想要访问远程服务,必须获取远程服务在Binder对象中对应的mRemote引用,获得该mRemote对象后,就可以调用其transact()方法,而在Binder驱动中,mRemote对象也重载了transact()方法,重载的内容主要包括以下几项:

  • 以线程间消息通信的模式,向服务端发送客户端传递过来的参数.
  • 挂起当前线程,当前线程正是客户端线程,并等待服务端线程执行完指定服务函数后通知(notify).
  • 接收到服务端线程的通知,然后继续执行客户端线程,并返回到客户端代码区.

对应用程序来讲,客户端似乎是直接调用远程服务对应的Binder,而事实上则是通过Binder驱动进行了中转.即存在两个Binder对象,一个是服务端的Binder对象,另一个是Binder驱动中的Binder对象,所不同的是Binder驱动中的对象不会再额外产生一个线程.

@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    return super.onTransact(code, data, reply, flags);
}
public final boolean transact(int code,Parcel data,Parcel reply, int flags){}

transact()的最后一个参数的含义是执行IPC调用的模式,分为两种:一种是双向,用常量0表示,其含义是服务端执行完指定服务后会返回一定的数据;另一种是单向,用常量1表示,其含义是不返回任何数据.

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

客户端请求AMS启动某个Service后,该Service如果正常启动,那么AMS就会远程调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含Service的Binder引用,然后在ApplicationThread中会回调bindService中的ServiceConnection接口.这样客户端就可以获取到远程服务的Binder引用了.

aidl工具可以把一个aidl文件转换为一个Java类文件,在该Java类文件,同时重载了transactonTransact方法,统一了存入Parcel和读取Parcel参数.

Parcel内只能写入以下三个类型的内容:

  • java原子类型,如int,long,String等变量.
  • Binder引用
  • 实现了Parcelable的对象.

oneway代表该service提供的方法都是没有返回值的,即都是void类型.

ServiceManager本身也是一个Service,Framework提供了一个系统函数,可以获取该Service对应的Binder引用,那就是BinderInternal.getContextObject().该静态函数返回ServiceManager后,就可以通过ServiceManager提供的方法获取其它系统Service的Binder引用.这种设计的好处是系统中仅暴露一个全局Binder引用,那就是ServiceManager,而其它系统服务则可以隐藏起来,从而有助于系统服务的扩展,以及调用系统服务的安全检查.其它系统服务在启动时,首先把自己的Binder对象传递给ServiceManager,即所谓的注册(addService).

Manager所manage的对象是服务本身,因为每个具体的服务一般都会提供多个API接口,而Manager所manage的正是这些API.客户端一般不能直接通过Binder引用去访问具体的服务,而是要经过一个Manager,相应的Manager类对客户端是可见的,而远程的服务类对客户端则是隐藏的.而这些Manager的类内部都会有一个远程服务Binder的变量,而且在一般情况下,这些Manager的构造函数参数中会包含这个Binder对象.简单地讲,即先通过ServiceManager获取远程服务的Binder引用,然后使用这个Binder引用构造一个客户端本地可以访问的经纪人,然后客户端就可以通过该经纪人访问远程的服务.

这种设计的作用是屏蔽直接访问远程服务,从而可以给应用程序提供灵活可控的API接口.

results matching ""

    No results matching ""