binder 一个简单的c++服务的实现,与callback实现

来源:互联网 发布:视 ar软件 编辑:程序博客网 时间:2024/04/29 18:41

 

 研究了android binder 有两天了,感觉这是一个简单易用的东西,也许以后在非android的应用环境中也可以使用这种IPC方案,所以把一些学习记录下来,以将来备用.

今天主要是实现了一个简单的c++ service服务程序,客户端通过binder呼叫服务上的,已经注册的接口函数。并在客户端实现了一个callback接口。

关于callback的接口这个例子只是一个简单的实现。估计以后实际使用中还有变数。

关于callback接口的一些想法

a. 现有测试程序中的client端并没有启动 IPCThreadState的joinThreadPool 函数

b. 现有测试程序中的client端并没有启动 ProcessState 的startThreadPool 函数

c. 现有测试程序中的client端的callback触发,是通过client主动调用service端的一个函数.在这个函数内回调,之前注册的callback接口中的函数,实现的。

d. 现在这种模式的测试通过,说明了service和client是可以双向沟通的

e. 将来的实现模式中,如果service端在需要时主动callback回来,估计client 端就需要启动

startThreadPool 函数了,至于 joinThreadPool 我目前的看法是没必要启动的。因为只要有了threadpool 客户端就可以实现服务了,当然,client端可不能随便退出来,至少退出来前要通知service端,自己已经退出,要不service端回调回来可就找不到北了.

以下贴出代码,以备后用:

一. 编写一个公用的动态库 libITestBinderInterface01

这个动态库为service端和client端共用。

 

Android.mkLOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= \TestBinderInterface01.cpp \ITestBinderInterface01.cpp base := /mnt/usbdisk/infoDroid2.2-1.8/infodroid-2.2/infodroid/frameworks/base/includeLOCAL_C_INCLUDES := \$(JNI_H_INCLUDE) \$(base)LOCAL_SHARED_LIBRARIES := \libutils \liblog \libbinderLOCAL_PRELINK_MODULE := falseLOCAL_MODULE := libITestBinderInterface01include $(BUILD_SHARED_LIBRARY) //Android.mk end


二.动态库的实现


//ITestBinderInterface01.h#ifndef ITESTBINDERINTERFACE01_H#define ITESTBINDERINTERFACE01_H#include <utils/RefBase.h>#include <binder/IInterface.h>#include <binder/Parcel.h>#include <binder/IMemory.h>namespace android {//call back interface ,call by serviceclass ITestBinderInterface01_CB : public IInterface{public:enum {CALLBACK01 = IBinder::FIRST_CALL_TRANSACTION,CALLBACK02};public:DECLARE_META_INTERFACE(TestBinderInterface01_CB);virtual void notifyCallback01(int32_t msgType, int32_t ext1, int32_t ext2) = 0;//call from service virtual void notifyCallback02(int32_t msgType, const sp<IMemory>& pmem) = 0;//test IMemory interface todo};class ITestBinderInterface01 : public IInterface{public:enum {SETCALLBACK = IBinder::FIRST_CALL_TRANSACTION,ADD,CALLBACKTEST};public:DECLARE_META_INTERFACE(TestBinderInterface01);virtual int InitParam(const sp<ITestBinderInterface01_CB>& callback) = 0;//init parametervirtual int Add(int a,int b) = 0; //return a+bvirtual int CallbackTest() = 0; //force callback};class BnTestBinderInterface01: public BnInterface<ITestBinderInterface01>{private:protected:public:virtual status_t onTransact( uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags = 0);};class BnTestBinderInterface01_CB: public BnInterface<ITestBinderInterface01_CB>{private:protected:public:virtual status_t onTransact( uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags = 0);};}; //namespace#endif


//---------------------------------------------------------------------------------------

ITestBinderInterface01.cpp#include <stdint.h>#include <sys/types.h>#include <binder/Parcel.h>#include <binder/IPCThreadState.h>#include <binder/IServiceManager.h>#include "ITestBinderInterface01.h"namespace android {class BpTestBinderInterface01: public BpInterface<ITestBinderInterface01>{public:BpTestBinderInterface01(const sp<IBinder>& impl): BpInterface<ITestBinderInterface01>(impl){}virtual int InitParam(const sp<ITestBinderInterface01_CB>& callback)//init parameter{Parcel data, reply;// data.writeInterfaceToken(ITestBinderInterface01::getInterfaceDescriptor());//why do that?? tododata.writeStrongBinder(callback->asBinder());remote()->transact(ITestBinderInterface01::SETCALLBACK, data, &reply);return (reply.readInt32());}virtual int Add(int a,int b)  //return a+b{Parcel data, reply;// data.writeInterfaceToken(ITestBinderInterface01::getInterfaceDescriptor());//why do that?? tododata.writeInt32(a); data.writeInt32(b);remote()->transact(ITestBinderInterface01::ADD, data, &reply);return (reply.readInt32());}virtual int CallbackTest()  //force callback{Parcel data, reply;// data.writeInterfaceToken(ITestBinderInterface01::getInterfaceDescriptor());//why do that?? todoremote()->transact(ITestBinderInterface01::CALLBACKTEST, data, &reply);return (reply.readInt32());}};IMPLEMENT_META_INTERFACE(TestBinderInterface01, "android.hardware.ITestBinderInterface01");class BpTestBinderInterface01_CB: public BpInterface<ITestBinderInterface01_CB>{public:BpTestBinderInterface01_CB(const sp<IBinder>& impl): BpInterface<ITestBinderInterface01_CB>(impl){}virtual void notifyCallback01(int32_t msgType, int32_t ext1, int32_t ext2){Parcel data, reply;// data.writeInterfaceToken(ITestBinderInterface01_CB::getInterfaceDescriptor());//why do that?? tododata.writeInt32(msgType);data.writeInt32(ext1);data.writeInt32(ext2);remote()->transact(ITestBinderInterface01_CB::CALLBACK01, data, &reply);}virtual void notifyCallback02(int32_t msgType, const sp<IMemory>& pmem) //return a+b{Parcel data, reply;// data.writeInterfaceToken(ITestBinderInterface01_CB::getInterfaceDescriptor());//why do that?? tododata.writeInt32(msgType); data.writeStrongBinder(pmem->asBinder());remote()->transact(ITestBinderInterface01_CB::CALLBACK02, data, &reply);}};IMPLEMENT_META_INTERFACE(TestBinderInterface01_CB, "android.hardware.TestBinderInterface01_CB");// ----------------------------------------------------------------------status_t BnTestBinderInterface01::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){switch(code) {case SETCALLBACK: {sp<ITestBinderInterface01_CB> callback = interface_cast<ITestBinderInterface01_CB>(data.readStrongBinder());reply->writeInt32(InitParam(callback));return NO_ERROR;} break;case ADD: {int a = data.readInt32();int b = data.readInt32();reply->writeInt32(Add(a,b));return NO_ERROR;} break;case CALLBACKTEST: {reply->writeInt32(CallbackTest());return NO_ERROR;} break;default:return BBinder::onTransact(code, data, reply, flags);}}status_t BnTestBinderInterface01_CB::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){switch(code) {case CALLBACK01: {int32_t msgType = data.readInt32();int32_t ext1 = data.readInt32();int32_t ext2 = data.readInt32();notifyCallback01(msgType, ext1, ext2);return NO_ERROR;} break;case CALLBACK02: {int32_t msgType = data.readInt32();sp<IMemory> pmem = interface_cast<IMemory>(data.readStrongBinder());notifyCallback02(msgType, pmem);return NO_ERROR;} break;default:return BBinder::onTransact(code, data, reply, flags);}}// ----------------------------------------------------------------------------}; // namespace android


 

//至此 接口部分实现完了,接下来做一个简单的实现


 

TestBinderInterface01.h#ifndef TESTBINDERINTERFACE01_H#define TESTBINDERINTERFACE01_H#include "ITestBinderInterface01.h"namespace android {class TestBinderInterface01 : public BnTestBinderInterface01{public:static void instantiate();virtual int InitParam(const sp<ITestBinderInterface01_CB>& callback) ;//init parametervirtual int Add(int a,int b) ; //return a+bvirtual int CallbackTest() ; //force callbackprivate:TestBinderInterface01();sp<ITestBinderInterface01_CB> _callback;public:virtual ~TestBinderInterface01();};class TestBinderInterface01_CB : public BnTestBinderInterface01_CB{public:virtual void notifyCallback01(int32_t msgType, int32_t ext1, int32_t ext2);//call from service virtual void notifyCallback02(int32_t msgType, const sp<IMemory>& pmem) ;//test IMemory interface todopublic:TestBinderInterface01_CB();virtual ~TestBinderInterface01_CB();};}; // namespace android#endif


//---------------------------------------------------------------------

TestBinderInterface01.cpp#define LOG_TAG "TestBinderInterface01"#include <utils/Log.h>#include <binder/IServiceManager.h>#include <binder/IPCThreadState.h>#include <utils/String16.h>#include <utils/Errors.h>#include <binder/MemoryBase.h>#include <binder/MemoryHeapBase.h>#include <ui/Overlay.h>#include <hardware/hardware.h>#include "TestBinderInterface01.h"#include <cutils/atomic.h>namespace android {extern "C" {#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <pthread.h>#include <signal.h>#include <sys/ioctl.h>}void TestBinderInterface01::instantiate() {defaultServiceManager()->addService(String16("kali.testbinder01"), new TestBinderInterface01);}TestBinderInterface01::TestBinderInterface01() :BnTestBinderInterface01(){LOGI("TestBinderInterface01 started: pid=%d", getpid());}TestBinderInterface01::~TestBinderInterface01(){}int TestBinderInterface01::InitParam(const sp<ITestBinderInterface01_CB>& callback){_callback = callback;printf("[service] InitParam pid=%d,tid=%d\n",getpid(),gettid());return 0;}int TestBinderInterface01::Add(int a,int b){printf("[service] Add a=%d,b=%d pid=%d,tid=%d\n",a,b,getpid(),gettid());return (a+b);}int TestBinderInterface01::CallbackTest(){printf("[service] CallbackTest pid=%d,tid=%d\n",getpid(),gettid());if( _callback.get() ){printf("[service] call notifyCallback01 \n");_callback->notifyCallback01(0, 1, 2);}return 0;}TestBinderInterface01_CB::TestBinderInterface01_CB(){}TestBinderInterface01_CB::~TestBinderInterface01_CB(){}void TestBinderInterface01_CB::notifyCallback01(int32_t msgType, int32_t ext1, int32_t ext2){printf("is call back01: msgType=%d,ext1=%d,ext2=%d pid=%d,tid=%d\n",msgType,ext1,ext2,getpid(),gettid());}void TestBinderInterface01_CB::notifyCallback02(int32_t msgType, const sp<IMemory>& pmem){printf("is call back02 pid=%d,tid=%d\n",getpid(),gettid());}};//namespace android//---------------------------------------------------------------------


好了。动态库libITestBinderInterface01 实现好了,mm一下就行了

接下来实现一个测试用的service和client。Android.mk如下。把两个程序的编译写在一起方便些

testApp/Android.mk

# Copyright (C) 2008 The Android Open Source Project
# #
# # Licensed under the Apache License, Version 2.0 (the "License");
# # you may not use this file except in compliance with the License.
# # You may obtain a copy of the License at
# #
# # http://www.apache.org/licenses/LICENSE-2.0
# #
# # Unless required by applicable law or agreed to in writing, software
# # distributed under the License is distributed on an "AS IS" BASIS,
# # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# # See the License for the specific language governing permissions and
# # limitations under the License.


LOCAL_PATH := $(call my-dir)


# HAL module implemenation, not prelinked and stored in
# hw/<HWCURSOR_HARDWARE_MODULE_ID>.<ro.product.board>.so
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_SHARED_LIBRARIES := liblog libcutils liblx_ipc libITestBinderInterface01
#LOCAL_SHARED_LIBRARIES := lpthread libcutils libc

LOCAL_SRC_FILES := main_BinderTestService.cpp

LOCAL_MODULE := BinderTestService
#LOCAL_CFLAGS:= -DLOG_TAG="hwcursor"
include $(BUILD_EXECUTABLE)

#client

include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_SHARED_LIBRARIES := liblog libcutils liblx_ipc libITestBinderInterface01
#LOCAL_SHARED_LIBRARIES := lpthread libcutils libc

LOCAL_SRC_FILES := main_BinderTestClient.cpp

LOCAL_MODULE := BinderTestClient
#LOCAL_CFLAGS:= -DLOG_TAG="hwcursor"
include $(BUILD_EXECUTABLE)

//Android.mk end ---------------------------------------

简单的service端:

testApp/main_BinderTestService.cpp#include <sys/types.h>#include <unistd.h>#include <grp.h>#include <binder/IPCThreadState.h>#include <binder/ProcessState.h>#include <binder/IServiceManager.h>#include <utils/Log.h>#include "../TestBinderInterface01.h"using namespace android;int main(int argc, char** argv){sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager();printf("TestBinderInterface01 pid=%d,tid=%d, is running...\n",getpid(),gettid());LOGI("ServiceManager: %p", sm.get());TestBinderInterface01::instantiate();ProcessState::self()->startThreadPool(); //启动线程池.这样binder驱动在需要时可以随时从驱动里返回 BR_SPAWN_LOOPER 让IPCThreadState类的executeCommand函数响应,并可以执行 case BR_SPAWN_LOOPER: mProcess->spawnPooledThread(false);break;看了半天才知道这个线程池是这么用的。不容易啊IPCThreadState::self()->joinThreadPool(); //我试过,换成while(1) usleep(100); 一样可行,因为上面的threadpool已经启动了,驱动可以主要要求启线程了}


 

//------------------------------------------------------------

testApp/main_BinderTestClient.cpp 一个简单的客户端

#include <sys/types.h>#include <unistd.h>#include <grp.h>#include <binder/IPCThreadState.h>#include <binder/ProcessState.h>#include <binder/IServiceManager.h>#include <utils/Log.h>#include "../TestBinderInterface01.h"using namespace android;Mutex mLock;sp<ITestBinderInterface01> getTestService() {Mutex::Autolock _l(mLock);sp<ITestBinderInterface01> pTestService;sp<IServiceManager> sm = defaultServiceManager();sp<IBinder> binder;do {binder = sm->getService(String16("kali.testbinder01"));if (binder != 0)break;LOGW("kali.testbinder01 not published, waiting...");usleep(500000); // 0.5 s} while(true);pTestService = interface_cast<ITestBinderInterface01>(binder);LOGE_IF(pTestService==0, "no FingerScanService!?");return pTestService;}int main(int argc, char** argv){// sp<ProcessState> proc(ProcessState::self());sp<ITestBinderInterface01> pTestService = getTestService();printf("[client] running pid=%d,tid=%d\n",getpid(),gettid());printf("[client] call InitParam\n");pTestService->InitParam(new TestBinderInterface01_CB());printf("[client] call Add result =%d \n",pTestService->Add(10,20));printf("[client] call CallbackTest\n");pTestService->CallbackTest();printf("[client] end\n");// TestBinderInterface01::instantiate();// ProcessState::self()->startThreadPool();// IPCThreadState::self()->joinThreadPool();}//------------------------------代码结束


 

mm 一下,生成

BinderTestService

BinderTestClient

libITestBinderInterface01.so

运行

BinderTestService &

BinderTestClient &

输出结果如下:

# ./BinderTestService &
# TestBinderInterface01 pid=2503,tid=2503, is running...

#
# ./BinderTestClient &
# [client] running pid=2506,tid=2506
[client] call InitParam
[service] InitParam pid=2503,tid=2504
[service] Add a=10,b=20 pid=2503,tid=2505
[client] call Add result =30
[client] call CallbackTest
[service] CallbackTest pid=2503,tid=2504
[service] call notifyCallback01
is call back01: msgType=0,ext1=1,ext2=2 pid=2506,tid=2506
[client] end

不错,结果是想像中的那样。我好像对IMemory 这个接口还不太会用,这个接口从名字上来看,应该很有用,可以高效传输大内存块的.过两天有空了再学学

 

原创粉丝点击