【内核研究】保证包裹内参数顺序aidl工具的使用(下)

来源:互联网 发布:ssh 命令 端口号 编辑:程序博客网 时间:2024/05/16 15:58

这些代码主要完成以下三个任务。

定义一个Java interface,内部包含aidl文件所声明的服务函数,类名称为IMusicPlayerService,并且该类基于IInterface接口,即需要提供一个asBinder()函数。

定义一个Proxy类,该类将作为客户端程序访问服务端的代理。所谓的代理主要就是为了前面所提到的第二个重要问题--统一包裹内写入参数的顺序。

定义一个Stub类,这是一个abstract类,基于Binder类,并且实现了IMusicPlayerService接口,主要由服务端来使用。该类之所以要定义为一个abstract类,是因为具体的服务函数必须由程序员实现,因此,IMusicPlayerService接口中定义的函数在Stub类中可以没有具体实现。同时,在Stub类中重载了onTransact()方法,由于transact()方法内部给包裹内写入参数的顺序是由aidl工具定义的,因此,在onTransact()方法中,aidl工具自然知道应该按照何种顺序从包裹中取出相应参数。

在Stub类中还定义了一些int常量,比如TRANSACTION_start,这些常量与服务函数对应,transact()和onTransact()方法的第一个参数code的值即来源于此。

刚接触IMusicPlayerService时,对以上描述的三个任务不容易从代码中看出,原因是这三个任务似乎更应该是分离的三个类,而aidl工具却把这些都放入了一个类中。理论上讲,的确可以把这三个任务写成三个类,但那会增加代码维护的烦琐。

在Stub类中,除了以上所述的任务外,Stub还提供了一个asInterface()函数。提供这个函数的作用是这样的:首先需要明确的是,aidl所产生的代码完全可以由应用程序员手工编写,IMusicPlayerService中的函数只是一种编码习惯而已,asInterface即如此,提供这个函数的原因是服务端提供的服务除了其他进程可以使用外,在服务进程内部的其他类也可以使用该服务,对于后者,显然是不需要经过IPC调用,而可以直接在进程内部调用的,而Binder内部有一个queryLocalInterface(String description)函数,该函数是根据输入的字符串判断该Binder对象是一个本地的Binder引用。在如图5-1所示中曾经指出,当创建一个Binder对象时,服务端进程内部创建一个Binder对象,Binder驱动中也会创建一个Binder对象。如果从远程获取服务端的Binder,则只会返回Binder驱动中的Binder对象,而如果从服务端进程内部获取Binder对象,则会获取服务端本身的Binder对象。听起来有点复杂。


因此,asInterface()函数正是利用了queryLocalInterface()方法,提供了一个统一的接口。无论是远程客户端还是本地端,当获取Binder对象后,可以把获取的Binder对象作为asInterface()的参数,从而返回一个IMusicPlayerService接口,该接口要么使用Proxy类,要么直接使用Stub所实现的相应服务函数。

0 0
原创粉丝点击