Android创建Native Binder Service
16lz
2021-01-24
Android创建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的具体实现,代码如下:
LOCAL_PATH := $(call my-dir)#生成binder service的服务端include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES := \libcutils \libutils \libbinderLOCAL_MODULE := TestServerLOCAL_SRC_FILES := \TestService.cpp \ITestService.cppLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)include $(CLEAR_VARS)LOCAL_SHARED_LIBRARIES := \libcutils \libutils \libbinderLOCAL_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 <stdio.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>using namespace android;namespace android{ class ITestService : public IInterface { <span style="white-space:pre"></span>public: <span style="white-space:pre"></span>/*使用该宏,相当于添加了一些代码,后面会有详细分析*/ DECLARE_META_INTERFACE(TestService); // declare macro virtual void test()=0; }; enum { TEST = IBinder::FIRST_CALL_TRANSACTION, }; class BnTestService: public BnInterface<ITestService> {<span style="white-space:pre"></span>public:<span style="white-space:pre"></span>virtual status_t<span style="white-space:pre"></span>onTransact(uint32_t code, const Parcel& data, Parcel* reply,uint32_t flags = 0); virtual void test() { printf("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(uint_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)
int main() {sp < IServiceManager > sm = defaultServiceManager();sp < IBinder > binder = sm->getService(String16("service.testservice"));sp<ITestService> cs = interface_cast < ITestService > (binder);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" namespace android { class TestService: public BnTestService { public: TestService(); ~TestService(); void test(); }; TestService::TestService() { } TestService::~TestService() { } void TestService::test() { printf("hello test\n"); }} int main() { sp < ProcessState > proc(ProcessState::self()); sp < IServiceManager > sm = defaultServiceManager(); sm->addService(String16("service.testservice"), new 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() { printf("Now get test\n"); } };
BnInterface也是binder核心库和框架中的类,表示binder实体类,在onTransact函数里,会根据客户端提交的操作代码调用不同的函数,而操作代码就是2)里声明的枚举值,在本实例里是TEST,我们收到test后会调用test方法。本实例里将onTransact的实现放在下面的代码中实现:
IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService"); status_t BnTestService::onTransact(uint_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推到/data/local/tmp,并修改权限 adb push TestServer /data/local/tmp adb push TestClient /data/local/tmp adb shell chmod 755 /data/local/tmp/* 然后开两个cmd窗口测试:
更多相关文章
- Android(安卓)Activity启动(二) App内部activity跳转过程及原理
- LinearLayout和RelativeLayout绘制过程的对比
- Android(安卓)利用 APT 技术在编译期生成代码
- Android(安卓)ListView的背景和黑色边缘化的问题
- 利用ActivityInstrumentationTestCase2测试Activity
- Android工程编译时报 Error running app: Default Activity not
- Android(安卓)JNI开发入门之一
- Android开发者编码风格
- android开发之Parcelable使用详解