Android(安卓)Binder开发实战指南之创建Native Binder Service
Android Binder开发实战指南之创建Native Binder Service
今天是2015.01.09,这一段时间是我工作中特别郁闷的一段日子,公司不景气同时也接近年过了,重新找一份工作也不是特别好的时候。这是一段非常时期,对于程序员来说,那就只能是代码中需求安慰了。这一段时间主要精力都放在看Android源码相关的东西上面了,正好看到网上关于Android创建native binder service相关的只是比较少,在这里我以一个实例来讲解关于怎么在Android下创建Native Binder Service。
首先在编译Binder相关的程序需要链接到Binder动态链接库,应用开发环境下使用ndk编程是不能链接binder动态链接库的,故此需要在源码开发环境下进行,本实例是放在Android源码目录的vender目录下面,然后创建一个NativeBinder文件夹,该文件夹的目录结构如下:
Android.mk 这个不用多说
Test.h 里面定义了本地方法的相关接口和本地接口代理BBxxxx
ITestService.cpp 里面定义了Bpxxxx和Bnxxxx::onTransact
TestService.cpp 这个就是Natavite Binder的实现
TestClient.cpp 这个就是通过Binder对Nataive Binder Service的使用了
1)Android.mk的具体实现,代码如下:
#生成binder native service的服务端include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES := \libcutils \libutils \libbinder \liblogLOCAL_MODULE := TestServerLOCAL_SRC_FILES := \TestService.cpp \ITestService.cppLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE) include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES := \libcutils \libutils \libbinder \liblog#生成binder native service的客户端LOCAL_MODULE := TestClientLOCAL_SRC_FILES := \ITestService.cpp \TestClient.cppLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)
关于Android.mk的相关语法问题,我在这里就不多做细说了,如果还不太了解的可以上百度或者谷歌去需求帮助。
2)Android Native Binder Service接口的定义,Test.h具体就是做的这个工作,下面给出代码
#ifndef TEST_H_H#define TEST_H_H#include #include #include #include //flock's head#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace android;#define LOGE(TAG,...) if(1) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__);#define TAG "NativeService"namespace android{ class ITestService : public IInterface { public: /*使用该宏,相当于添加了一些代码,后面会有详细分析*/ DECLARE_META_INTERFACE(TestService); // declare macro virtual void test()=0; }; enum { TEST = IBinder::FIRST_CALL_TRANSACTION, }; class BnTestService: public BnInterface {public:virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,uint32_t flags = 0);virtual void test(){LOGE(TAG,"Now get test\n");} };}#endif
(1)使用DECLARE_META_INTERFACE(TestService);相当于添加了下述代码:
static const android::String16 descriptor; static android::sp asInterface( const android::sp& obj); virtual const android::String16& getInterfaceDescriptor() const; ITestService (); virtual ~ITestService();
(2)为ITestService接口的所有方法声明枚举,一个枚举值对应ITestService接口的一个方法(Test.h)
enum { TEST = IBinder::FIRST_CALL_TRANSACTION, };
TEST相当于ITestService接口里的test方法,后续会为该枚举值调用test方法(Test.h)
在这里我想多说两句,如果大家手里有源码的话,可以参照Android多媒体框架的相关源码来学习这里,我这里为什么这样写也不是我自己独创,我也是参照Android源码来进行的。网上说为什么将BnTestService定义在头文件中,而不将BPTestService定义在头文件中,网上所说的是BPTestService对用户是透明的,这个我也没有弄清楚为什是透明的就不定义在这个头文件中呢,这个不在我们这里的讨论范畴之内,就不花多余的时间讨论了。
3)ITestService.cpp,该文件主要创建了BpTestService和实现了BnTestService::onTransact,不多说直接上代码:
#include "Test.h"namespace android{class BpTestService:public BpInterface{public:BpTestService(const sp& impl):BpInterface(impl){}void test(){printf("in the get Test\n"); Parcel data, reply; data.writeInterfaceToken(ITestService::getInterfaceDescriptor()); remote()->transact(TEST, data, &reply); printf("send Print %d\n", reply.readInt32());}};IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService");status_t BnTestService::onTransact(uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags) {switch (code) {case TEST: {printf("got the client msg\n");CHECK_INTERFACE(ITest, data, reply);test();reply->writeInt32(100);return NO_ERROR;}break;default:break;}return NO_ERROR;}}
这里我想重点说明的是,该处的IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService");和DECLARE_META_INTERFACE(TestService); // declare macro是相互对应的,这个需要大家关注下。写到这里,Android下创建的Native Binder Service的工作已经进行了一大半了,接下来的只需要进行具体操作使用就OK了。
4)实现ITestService接口的方法(ITestService.cpp)
IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService");
使用IMPLEMENT_META_INTERFACE(TestService, “android.TestServer.ITestService”);相当于添加了下述代码:
/*初始化用宏DECLARE_META_INTERFACE声明的静态字段descriptor*/const android::String16 ITestService::descriptor("android.TestServer.ITestService");/*实现用宏DECLARE_META_INTERFACE声明的方法getInterfaceDescriptor */const android::String16& ITestService::getInterfaceDescriptor() const { return ITestService::descriptor; } /*实现用宏DECLARE_META_INTERFACE声明的方法asInterface */android::sp ITestService::asInterface( const android::sp& obj) { android::sp intr; if (obj != NULL) { /*在binder实体类BnInterface里会执行queryLocalInterface*/ intr = static_cast( obj->queryLocalInterface( ITestService::descriptor).get()); /*在binder引用类BpInterface里会创建BpInterface的子类对象*/ if (intr == NULL) { intr = new BpTestService(obj); } } return intr; } /*实现用宏DECLARE_META_INTERFACE声明的构造器和析构器 */ITestService::ITestService() { } ITestService::~ITestService() { };
5)实现Client端(TestClient.cpp)
#include "Test.h"using namespace android;#define TAG "TestClient"int main(){sp < IServiceManager > sm = defaultServiceManager();sp < IBinder > binder = sm->getService(String16("service.testservice"));sp cs = interface_cast (binder);LOGE(TAG,"Hello Native service\n");cs->test();return 0;}
Service的Client通过Service Manager拿到的ITestService接口对象其实就是一个binder引用,也就是说其实是一个BpTestService对象,它也会实现ITestService接口的test方法,但是它并没有实现test的功能,而是跨进程调用Binder实体对象BnInterface的test方法。因为
涉及到跨进程调用,所以并没有直接调用,而是通过binder驱动转交给服务进程一些参数,然后就阻塞住。服务进程收到这些参数后,知道client端调用test方法,此时服务端调用test方法,执行完成后把执行结果通过binder驱动再返回给client所在进程,此时client的test方法收到结果后
再返回。
我们再实际的开发过程中并没有直接和binder驱动交互,而是通过Android为binder专门设计的一些核心库和框架来交互,这样就简化了代码编写复杂度。像BpInterface便是核心库和框架提供的一个类,我们在实现时,只需要调用BpInterface的构造器,并实现ITestService接口的test方
法即可,实现test方法时,通过remote()调用transact方法就能把数据提交至service端,servcie的返回结果会放在reply里。interface_cast(binder)实际上调用的方法是用宏DECLARE_META_INTERFACE声明的方法ITestService::asInterface,这里用了内联函数模版。
ProcessState和IPCThreadState是真正直接和binder驱动交互的类,核心库和框架层都是通过和这两个类交互才能和驱动间接交互。它们通过ioctl和binder驱动交互,ProcessState主要负责管理所有的binder引用,IPCThreadState则和binder传输数据。以后如果有时间再详细介绍这两个类。
6)实现Service端(ServiceTest.cpp)
#include "Test.h"#define TAG "TestService"namespace android { class TestService: public BnTestService { public: TestService(); ~TestService(); void test(); }; TestService::TestService() { } TestService::~TestService() { } static int getCallPackageName(char *processName) { long pid = 0; pid = IPCThreadState::self()->getCallingPid(); int ret; char cmdline[256] = {0}; char buf[128] = {0}; sprintf(cmdline, "/proc/%d/cmdline", pid); int fd =0; fd = open(cmdline, O_RDONLY); if (fd < 0) { LOGE("PERSSION","open /proc/xxx/cmdline error"); return -1; } ret = read(fd, buf, sizeof(buf)); if (ret <= 0) { LOGE("PERSSION","read /proc/xxx/cmdline error"); close(fd); return -1; } close(fd); LOGE("PERSSION","current pid = %d , package name = %s", getpid(), buf); strcpy(processName,buf); return 0; } void TestService::test() { char processName[256] = {0};getCallPackageName(processName); printf("hello test\n");LOGE(TAG,"hello test from %s\n", processName); } } int main() { sp < ProcessState > proc(ProcessState::self()); sp < IServiceManager > sm = defaultServiceManager(); sm->addService(String16("service.testservice"), new TestService()); //启动服务 LOGE(TAG,"Start testservice"); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; }
其中声明并实现binder实体类BnInterface是如下代码实现的,定义在Test.h文件中,定义如下:
class BnTestService: public BnInterface {public:virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,uint32_t flags = 0);virtual void test(){LOGE(TAG,"Now get test\n");} };
BnInterface也是binder核心库和框架中的类,表示binder实体类,在onTransact函数里,会根据客户端提交的操作代码调用不同的函数,而操作代码就是2)里声明的枚举值,在本实例里是TEST,我们收到test后会调用test方法。本实例里将onTransact的实现放在下面的代码中实现:
IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService");status_t BnTestService::onTransact(uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags) {switch (code) {case TEST: {printf("got the client msg\n");CHECK_INTERFACE(ITest, data, reply);test();reply->writeInt32(100);return NO_ERROR;}break;default:break;}return NO_ERROR;}
在这里的onTransact调用了test()方法。
7)最后是执行,查看结果
将TestServer和TestClient推到/system/bin,并修改权限
adb push TestServer /system/bin
adb push TestClient /system/bin
具体见如下图示
然后开两个cmd窗口测试:
服务端
客户端
最后统一奉上源码Binder实战大荟萃
更多相关文章
- 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
- Android(安卓)View框架总结(一)
- 转:Android(安卓)判断用户2G/3G/4G移动数据网络
- Android(安卓)生成竖直方向的条形码
- android的tone音源代码DTMF双音频何快速计算正弦波
- 【移动开发】WIFI热点通信(二)
- Android上JNI的调试
- 【Android(安卓)源码解析】浅谈DecorView与ViewRootImpl
- 用Android访问本地站点---(localhost,10.0.2.2)要区别