標籤:android native service binder
Native Service其實就是一個linux守護進程,提供一些服務,不過由於android的進程間通訊使用了Binder機制,那麼我們就需要按照android的規則來實現我們的Native Service。
用戶端在請求service的服務時使用了一個具有相同介面的Proxy類。native service這具體實現這個介面,所以android提供了IInterface類,其是”base class for Binder interfaces”,所以我們的IZxTask類繼承它:
class IZxTask : public IInterface {public: enum { TASK_GET_PID = IBinder::FIRST_CALL_TRANSACTION, }; virtual int getPid() = 0; DECLARE_META_INTERFACE(ZxTask);};
IMPLEMENT_META_INTERFACE(ZxTask, "android.hardware.IZxTask");
必須以I開頭,因為後面會用到一些宏,比如DECLARE_META_INTERFACE,I開頭是寫到宏裡面的,所以我們只要傳入了ZxTask就行了。我們的Native Service提供一個介面就是返回Service的進程號。
下面我們就需要開始分化實現,一個是用戶端,一個是native service。
先來看代理類
class BpZxTask : public BpInterface<IZxTask> {public: BpZxTask(const sp<IBinder>& binder) : BpInterface<IZxTask>(binder) { } virtual int getPid() { Parcel data, reply; data.writeInterfaceToken(IZxTask::getInterfaceDescriptor()); remote()->transact(TASK_GET_PID, data, &reply); return reply.readInt32(); }};
BpInterface模板類,其中的p就是代理的意思。其以我們前面定義的Interface為模板參數。
BpInterface聲明如下:
template<typename INTERFACE>class BpInterface : public INTERFACE, public BpRefBase{public: BpInterface(const sp<IBinder>& remote);protected: virtual IBinder* onAsBinder();};
我們的BpZxTask需要實現我們定義的介面類中的介面函數。在實現中,我們是用戶端,我們需要向native service提申請,我們使用remote獲得關聯service的IBinder對象,然後通過transact提交,通過reply獲得傳回值。
下面來看BnInterface的實現。
class BnZxTask : public BnInterface<IZxTask> {public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);};
status_t BnZxTask::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch (code) { case TASK_GET_PID: { CHECK_INTERFACE(IZxTask, data, reply); int32_t pid = getPid(); reply->writeInt32(pid); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); }}
我們在bpinterface的transact調用會回調bninterface的onTransact來處理,我們根據code參數來進行請求的區分。
BnInterface類模板其聲明如下:
template<typename INTERFACE>class BnInterface : public INTERFACE, public BBinder{public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const;protected: virtual IBinder* onAsBinder();};
其一個父類是繼承自IInterface的介面類,一個是代表Binder service服務端的BBinder類。
下面來實現native service。
class ZxTaskService : public BinderService<ZxTaskService>, public BnZxTask {public: virtual int getPid(); static char const* getServiceName() { return "ZxTask"; } friend class BinderService<ZxTaskService>;};int ZxTaskService::getPid(){ return getpid();}
我們在此實現服務提供的getPid介面就ok,BinderService模板為我們啟動一個Service實現了邏輯封裝。
BinderService實現如下:
template<typename SERVICE>class BinderService{public: static status_t publish(bool allowIsolated = false) { sp<IServiceManager> sm(defaultServiceManager()); return sm->addService( String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated); } static void publishAndJoinThreadPool(bool allowIsolated = false) { publish(allowIsolated); joinThreadPool(); } static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; }private: static void joinThreadPool() { sp<ProcessState> ps(ProcessState::self()); ps->startThreadPool(); ps->giveThreadPoolName(); IPCThreadState::self()->joinThreadPool(); }};
其要求模板參數實現getServiceName方法,publish和publishAndJoinThreadPool函數實現了該service添加到SM的邏輯,publish只是add,而publishAndJoinThreadPool會啟動該service。
這裡我們就完成了native service的開發,我們將其編成庫。
Android.mk
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := ZxTask.cpp ZxTaskService.cppLOCAL_C_INCLUDES := system/core/include frameworks/native/includeLOCAL_SHARED_LIBRARIES := libbinder libutils LOCAL_MODULE:= libzxtaskinclude $(BUILD_SHARED_LIBRARY)
我們寫一個service的可執行程式。
main.cpp
#include "service/ZxTaskService.h"int main(){ /* code */ android::ZxTaskService::publishAndJoinThreadPool(); return 0;}
Android.mk
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := main.cpp LOCAL_C_INCLUDES := frameworks/base/zxTaskLOCAL_MODULE:= zxtaskserviceLOCAL_SHARED_LIBRARIES := libzxtask libutils libbinderinclude $(BUILD_EXECUTABLE)
寫一個測試用戶端
main.cpp
#include "service/ZxTask.h"#include <binder/IServiceManager.h>#include <unistd.h>#include <stdio.h>int main(){ using namespace android; sp<IServiceManager> sm =defaultServiceManager(); printf("%s\n", "get serviceManager"); sp<IBinder> binder =sm->getService(String16("ZxTask")); sp<IZxTask> mTask =interface_cast<IZxTask>(binder); printf("ZxTask Service pid %d, client pid:%d",mTask->getPid(), getpid()); return 0;}
Android.mk
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := main.cpp LOCAL_C_INCLUDES := frameworks/base/zxTaskLOCAL_MODULE:= zxtaskclientLOCAL_SHARED_LIBRARIES := libzxtask libutils libbinderinclude $(BUILD_EXECUTABLE)
其中用到了interface_cast。
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}
其使用了asInterface函數,而這個函數就是我們在IZxTask裡面使用DECLARE_META_INTERFACE聲明的。
#define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; static android::sp<I##INTERFACE> asInterface( \ const android::sp<android::IBinder>& obj); virtual const android::String16& getInterfaceDescriptor() const; I##INTERFACE(); \ virtual ~I##INTERFACE();
其聲明了一個描述的類屬性,我們使用的asInterface函數。
看下IMPLEMENT_META_INTERFACE宏。
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ const android::sp<android::IBinder>& obj) { android::sp<I##INTERFACE> intr; \ if (obj != NULL) { intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( I##INTERFACE::descriptor).get()); \ if (intr == NULL) { intr = new Bp##INTERFACE(obj); \ } } return intr; } I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \
主要看asInterface的實現。其會調用IBinder的queryLocalInterface查詢我們的介面對象,這裡使用了基類指標,如果沒有就new出來。我們的BpZxTask只有在這個函數中使用,這也是為什麼我在實現時,指示全部把它放在了cpp檔案中。
intr = new Bp##INTERFACE(obj);
這一句表明我們的Proxy類一定以Bp開頭且IBinder對象作為構造的參數傳入,實現了proxy和IBinder對象的綁定。
sp<IBinder> binder =sm->getService(String16("ZxTask"));
根據service名獲得這個service的IBinder對象,使用interface_cast實現了用戶端的Proxy和service的IBinder的綁定,然後我們在getPid中就可以調用IBinder的transact函數,這樣就和remote通訊上,回調到native service的onTransact的介面,然後處理了將結果返回,這樣就實現了client和service的通訊。
運行如:
代碼例子:https://git.oschina.net/zhouX/servicedemo.git
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android添加一個Native Service