分类: C/C++
研究了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端共用。
1.Android.mk
- LOCAL_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/include
- LOCAL_C_INCLUDES := \
- $(JNI_H_INCLUDE) \
- $(base)
- LOCAL_SHARED_LIBRARIES := \
- libutils \
- liblog \
- libbinder
-
- LOCAL_PRELINK_MODULE := false
- LOCAL_MODULE := libITestBinderInterface01
- include $(BUILD_SHARED_LIBRARY)
- #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 service
- class 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 parameter
- virtual int Add(int a,int b) = 0; //return a+b
- virtual 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
- #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?? todo
- data.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?? todo
- data.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?? todo
- remote()->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?? todo
- data.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?? todo
- data.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
点击(此处)折叠或打开
- #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 parameter
- virtual int Add(int a,int b) ; //return a+b
- virtual int CallbackTest() ; //force callback
-
- private:
- 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 todo
- public:
- TestBinderInterface01_CB();
- virtual ~TestBinderInterface01_CB();
- };
- }; // namespace android
- #endif
- //---------------------------------------------------------------------
- #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如下。把两个程序的编译写在一起方便些
点击(此处)折叠或打开
- # 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)
点击(此处)折叠或打开
- #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已经启动了,驱动可以主要要求启线程了
- }
- //------------------------------------------------------------
- #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