Chinaunix首页 | 论坛 | 博客
  • 博客访问: 167682
  • 博文数量: 24
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 399
  • 用 户 组: 普通用户
  • 注册时间: 2013-03-04 15:36
文章分类

全部博文(24)

文章存档

2017年(2)

2015年(5)

2014年(9)

2013年(8)

我的朋友

分类: Android平台

2015-02-09 22:03:09

Binder应用--实现自己的ServiceC++实现)

 

下面的C++代码实现了一个自己的Service,假设我这里要实现的服务接口为MyService,这里列出几个必要的文件:

 

Android.mk // 编译必需

IMyService.h // 定义IMyService接口类,

IMyService.cpp // 实现IMyService接口类

MyService.cpp // 实现MyService接口类,它是具体提供服务的类,并在这里注册服务

MyServiceTest.cpp // 使用MyService服务接口例子

 

与在JAVA层实现一个服务类似,先给出接口定义

------------------------------ IMyService.h----------------------------------------

#ifndef I_MY_SERVICE_H__

#define I_MY_SERVICE_H__


#include

#include

#include

#include


#include

#include

#include


class IMyService : public IInterface

{

public:

         DECLARE_META_INTERFACE(MyService);


         virtual int         doSomething(int) = 0;

        

         enum {

                   DO_SOMETHING = IBinder::FIRST_CALL_TRANSACTION,

         };

};


class BnMyService : public BnInterface

{

public:

         virtual status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0);

};


#endif

----------------------------------------------------------------------------------------

BnMyService表示服务端的本地Binder对象(n 的意思是native),一会会看到它确实是在服务端实例化的。再来看接口实现:

------------------------------ IMyService.cpp----------------------------------------

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

 

#include

#include

#include

 

namespace android {

 

#include "IMyService.h"

 

class BpMyService : public BpInterface

{

public:

         BpMyService(const sp& impl)

                   : BpInterface< IMyService >(impl)

         {

         }

 

         virtual int          doSomething(int);

};

 

int    BpMyService::doSomething(int x)

{

         Parcel data, reply;

 

         data.writeInterfaceToken(IMyService::getInterfaceDescriptor());

         data.writeInt32(x);

         remote()->transact(DO_SOMETHING, data, &reply);

         return reply.readInt32();

}

 

IMPLEMENT_META_INTERFACE(MyService, "android.myservice.IMyService");

 

status_t BnMyService::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)

{

         switch (code) {

         case INTERFACE_TRANSACTION:

                   LOGI("onTransact->INTERFACE_TRANSACTION\n");

                   //CHECK_INTERFACE(IMyService, data, reply); // 如果不注释掉这句就跑不下去,原因下面会有分析                  reply->writeString16(IMyService::getInterfaceDescriptor()); // 静态函数getInterfaceDescriptor()是在DECLARE_META_INTERFACE(MyService)当中定义,然后在IMPLEMENT_META_INTERFACE当中实现的

                   return NO_ERROR;

         case DO_SOMETHING:

                   LOGI("onTransact->DO_SOMETHING\n");

                   CHECK_INTERFACE(IMyService, data, reply);

                   reply->writeInt32(doSomething(data.readInt32()));

                   return NO_ERROR;

         }

 

         return NO_ERROR;

};

 

}

----------------------------------------------------------------------------------------

BpMyService表示客户端代理(p表示代理的意思),此类在客户端使用。什么时候使用,查看IMPLEMENT_META_INTERFACE就可以看到了。BnMyService::onTransact是在服务端调用的,当客户端使用remote()->transact向服务端发消息时,此函数就会被触发。具体底层如何实现,需要研究Binder驱动代码,这里不详细介绍。总之记住一句:Binder就是通过某种方式将消息从一端转到另一端。

 

接下来来实现MyService,并且实现一个MyService的服务端进程,将MyService注册到Android,然后等待提供服务

------------------------------ MyService.cpp----------------------------------------

namespace android {

 

#include "IMyService.h"

 

class MyService :

         public BinderService,

         public BnMyService

{

public:

         MyService()

         {

                   _x = 0;

                   LOGI("construct MyService\n");

         }

         ~MyService()

         {

                   LOGI("disconstruct MyService\n");

         }

// 此函数用于在注册服务时获取服务名称,在publishAndJoinThreadPool当中使用

         static const char *getServiceName() { return "service.MyService"; }

// 服务端提供服务的函数

         virtual int          doSomething(int x)

         {

                   int rx = _x;

                   LOGI("Hi doing something %d %d\n", _x, x);

                   _x += x;

                   return rx;

         }

 

private:

         int _x;

};

 

// 注册服务,静态函数publishAndJoinThreadPool在BinderService当中实现,BinderService类由Android提供,用于简化服务端的注册工作

void publishMyService()

{

         MyService::publishAndJoinThreadPool();

}

 

}

 

using namespace android;

// 这里使用MyService

int main(int argc, const char* const argv[])

{

         publishMyService();

 

         return 0;

}

----------------------------------------------------------------------------------------

服务端做为一个单独进程存在,客户端通过IServiceManager接口获取MyService的远程引用,然后通过此引用来得到服务。

下面是客户端调用的代码

---------------------------------MyServiceTest.cpp----------------------------------------

namespace android {

 

#include "IMyService.h"

 

void callRemoteService()

{

         sp service;

         String16 serviceName("service.MyService");

         getService(serviceName, &service);

 

         int y = service->doSomething(8);

         LOGI("y = %d\n", y);

}

 

}

 

using namespace android;

 

int main(int argc, const char* const argv[])

{

         callRemoteService();

 

         return 0;

}

----------------------------------------------------------------------------------------

getService(serviceName, &service);函数是Android提供的,内部实现其实还是通过defaultServiceManager()函数先获取远程ServiceManager引用,然后再通过ServiceManagerrgetService(...)函数来获取远程MyService的引用,代码实现请查看IServiceManager.h当中的status_t getService(const String16& name, sp* outService)

 

最后给出Android.mk,其中定义了两段编译指令,先编译服务端程序,再编译客户端程序。

---------------------------------Android.mk----------------------------------------

LOCAL_PATH:= $(call my-dir)

# 编译服务端程序

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

         IMyService.cpp \

         MyService.cpp

LOCAL_SHARED_LIBRARIES := \

         libutils \

         libbinder \

         libandroid_runtime

LOCAL_MODULE:= my_service

include $(BUILD_EXECUTABLE)

 

# 编译客户端例子程序

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

         IMyService.cpp \

         MyServiceTest.cpp

LOCAL_SHARED_LIBRARIES := \

         libutils \

         libbinder \

         libandroid_runtime

LOCAL_MODULE:= my_service_app

include $(BUILD_EXECUTABLE)

----------------------------------------------------------------------------------------

编译完成后可以在板子上运行了,启动my_service时要后台运行,因为它会阻塞,如果不在后台运行的话,后面的工作就无法在终端上完成了。

1.先用service list命令查看现有的服务列表,service程序是android提供的,代码在frameworks/base/cmds/service目录下。

       #service list

       发现了63个服务,下面来启动我的MyService

2. 启动MyService服务进程

       #./my_service &

3. 再用service list命令列出服务列表

       #service list

       看到变化了吗?这次发现了64个服务,而且第0个服务变成了service.MyService,先前的第0个服务现在变成第1个服务,说明我的服务已经注册成功了

         我在这里还遇到一个问题,就是[]中间显示的东西,例如[android.myservice.IMyService],起初我没有实现BnMyService::onTransact当中的case INTERFACE_TRANSACTION分支,结果这个[]中间显示为空,后来通过分析service list代码发现,这个[]中间的东西是通过客户端调用服务端的INTERFACE_TRANSACTION服务获取到的,后面我加上了case INTERFACE_TRANSACTION分支实现后,[]中的东西果断显示出来了。但此过程中我又注意到在case INTERFACE_TRANSACTION分支当中调用了CHECK_INTERFACE(IMyService, data, reply);时就无法返回结果,后来查看CHECK_INTERFACE的定义和service list的代码发现是因为service list在调用service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);之前没有调用data.writeInterfaceToken(...),这里没有调用也可以理解,因为他不知道要调用的是哪个服务。结果将data发到服务端经过CHECK_INTERFACE检查时发现此data不是针对MyService服务的,就出错返回了。这里也说明一个问题,你如果你希望case INTERFACE_TRANSACTION的东西能正确返回给service list命令,就不要调用CHECK_INTERFACE检查参数了。

4. 通过my_service_app程序调用MyService提供的服务

         #./my_service_app

       #logcat -s MyService

      从打印看已经调用成功了,可以再来重复一个第4步看看结果是什么

       我启动了MyService服务后,马上就打印了construct MyService,这说明服务端对象被创建,然后运行了两次my_service_app,第一次y = 0, 第二次y=8,这说明了服务端对象一旦创建后就一直存在。

 

总结:

1. IXXX仅实现接口,BpXXX表示代理,BnXXX表示服务端,分别对应三个接口类IInterface, BpInterface, BnInterface,通过c++实现服务时需要继续这几个接口类。

2.服务端对象一旦注册,不会自己销毁,而且是在注册时创建,我在想是不是可以将服务端理解成一个单件?……

3.BinderService类可以简化Service类的注册过程

4.一定要多折腾,折腾多了,遇到的问题就多,遇到的问题越多理解就越深入。最近因为蓝牙的问题,还接触到一些dbus的使用,感觉dbus用起来还是不如android提供的binder来的方便。不过dbus的运用还是很广的,只是我不熟悉罢了。

阅读(3881) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~