Android Binder开发实战指南之创建Native Binder Service

                         Android Binder开发实战指南之创建Native Binder Service

Android Binder实战开发指南目录:

Android Binder实战开发指南Native层获取Process进程名和调用者进程名

Android Binder实战开发指南之Java层直接调用Native Binder Service

Android Binder开发实战指南之创建Native Binder Service

Android Binder实战开发指南之Native层使用Java层Binder服务

Android Binder实战开发指南之创建Java层Binder系统服务

 

今天是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 \
	liblog
LOCAL_MODULE := TestServer
LOCAL_SRC_FILES := \
	TestService.cpp \
	ITestService.cpp
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
 
include $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libutils \
	libbinder \
	liblog

#生成binder native service的客户端
LOCAL_MODULE := TestClient
LOCAL_SRC_FILES := \
	ITestService.cpp \
	TestClient.cpp
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)

 

关于Android.mk的相关语法问题,我在这里就不多做细说了,如果还不太了解的可以上百度或者谷歌去需求帮助。

 

 2)Android Native Binder Service接口的定义,Test.h具体就是做的这个工作,下面给出代码

#ifndef TEST_H_H
#define TEST_H_H
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/file.h>//flock's head
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <android/log.h>
#include <cutils/properties.h>
#include <unistd.h>


#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <android/log.h>

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<ITestService>
	 {
		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<ITestService> asInterface(
     const android::sp<android::IBinder>& 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<ITestService>
	{
		public:
			BpTestService(const sp<IBinder>& impl):
			BpInterface<ITestService>(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> ITestService::asInterface(   
const android::sp<android::IBinder>& obj)      
{                                                      
 android::sp<ITestService> intr;                    
if (obj != NULL) {           
/*在binder实体类BnInterface里会执行queryLocalInterface*/                      
intr = static_cast<ITestService*>(             
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<ITestService> cs = interface_cast <ITestService> (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<ITestService>
	 {
		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实战大荟萃

 

 

 

 

 

 

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值