Jimmy Chen

A Programmer

Java跨层访问native(C/C++)注册的service

  进行Binder开发时,比较多是在同语言下进行的,比如在JAVA下可以手动实现或者通过AIDL实现,在C++下手动实现。但是Binder也是可以夸语言通信的,这里打算分两篇来进行说明,其中一篇是在通过native层实现service的代码,并注册到system_server中,在上层通过Java实现访问;另一篇则相反,在Java层中实现service的代码,在native通过程序访问;那下面开始看代码实现,不过需要注意的是这里面的代码添加相应的selinux权限,所以一切实验都是在开机后通过adb shell setenforce 0来关闭selinux后进行的。

native层实现service

  native层实现service也不难,博主在之前的博客也有写过,不过之前的service启动代码是集成到system_server中的,这次我们就不使用这种方式了,我们自己编写可执行程序来启动service,并且编写一个简单的测试程序。

IArithmeticService.h

这个是service和client都需要实现的基类,继承IInterface,其中需要特别注意的就是DECLARE_META_INTERFACE这个定义宏了,这个比较简单,没啥好说的。

IArithmeticService.cpp

这个类主要是用来实现上面.h中定义的代码

  上面主要体现的是binder同学的client端的实现,流程很简单,就是将调用端的数据打包成Parcel,然后通过transact发送到service端即可。因为在.h文件中我们使用了DECLARE_META_INTERFACE这个定义宏,所以在实现的时候使用的是IMPLEMENT_META_INTERFACE,注意传递给该宏的第二个参数”com.jimmy.service.ArithmeticService”,这个参数表示的是后面进行binder通信,客户端和服务端需要进行校验的Token。同时需要注意看,如果我们在client会通过writeInterfaceToken方法,将Token写入到Parcel中,那么在服务端就必须通过CHECK_INTERFACE来对Parcel中的Token进行校验,否则会导致Parcel中的数据读写顺序不一致,而导致出错的。最后还实现了Service端的onTransaction方法,该方法作用就是读取客户端传递过来的数据,然后调用实际工作的方法,然后见执行的结果再通过Parcel传递会给客户端。

  稍微总结一下就是,到目前位置,我们已经完成了客户端代理的代码和服务端onTransact的代码,剩下的就是具体服务端的代码实现。这里博主写的代码主要实现演示怎么实现binder客户端和服务端的,所以服务端的具体实现就很简单了,拿个四则运算作为服务端的具体实现了。

ArithmeticService.h

  头文件继承BnArithmeticService即可。

ArithmeticService.cpp

具体实现也很简单,没什么特殊的。另外博主讲注册service需要使用的代码也整合到这里了,主要就是调用defaultServiceManager的addservcie方法,这个方法就是给native调用的。

TestService.cpp

因为之前我们已经将添加服务的代码整合到service端的代码了,所以这里只需要调用就行,很简单,最后注意执行消息循环,不要让service进行退出就行。

TestClient.cpp

上面是native测试的代码,经典套路,getServcie然后转换一下调用即可。

Android.mk

这里给出编译用的Android.mk文件

Java层访问native service

  上面我们已经实现了native的服务了,那么我们应该如何在Java层来访问这个native层实现的服务呢?其实很简单,我们只需要查看native层方法实现的顺序,然后在Java层够着一个AIDL文件即可。下面是博主构造出的AIDL文件。需要特别说明的是:

  • AIDL文件里面的方法顺序一定要和native层中enum中定义的方法顺序一致才行,不然会出现方法调用错乱的问题,例如明明我调用的是add方法,可是结果确实mul的结果
  • AIDL文件的包名需要和native中IMPLEMENT_META_INTERFACE宏定义传入的Token一致,否则会出现因Token不匹配导致调用失败的问题

  AIDL构造出来后,一切就简单了,我们就可以直接在Java代码中调用AIDL的方法进行传输了

这样就可以了,相当的简单的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注