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实战大荟萃

 

 

 

 

 

 

更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. Android(安卓)View框架总结(一)
  3. 转:Android(安卓)判断用户2G/3G/4G移动数据网络
  4. Android(安卓)生成竖直方向的条形码
  5. android的tone音源代码DTMF双音频何快速计算正弦波
  6. 【移动开发】WIFI热点通信(二)
  7. Android上JNI的调试
  8. 【Android(安卓)源码解析】浅谈DecorView与ViewRootImpl
  9. 用Android访问本地站点---(localhost,10.0.2.2)要区别

随机推荐

  1. CentOS 7部署OpenStack--部署Newtron(计
  2. IPFS矿池集群方案详解
  3. CentOS 7部署OpenStack--创建第一台虚拟
  4. 《欢乐颂》中的互联网
  5. 中国唯一合法的虚拟货币是什么?
  6. iOS 面试秘籍全套
  7. Mac 版 Chrome 浏览器已支持 Tab Throttl
  8. BAT iOS面试对答题
  9. 金三银四涨薪季,这些面试题你掌握了嘛?
  10. Android TCP Socket通信客户端/服务器端D