跨進程C/S native service服務編寫

純Native的Service表示代碼都在Native層,前面的文章講到瞭兩個service進程通過這binder中的onTransacton進行通訊,而這篇文章主要講利用C/S結構的方法,利用IInterface進行相互訪問。

以具體代碼為例:
test.cpp :
using namespace android;

int main(int argc, char** argv)
{
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    LOGI("ServiceManager: %p", sm.get());
    sm->addService("test.service",new Test);  //這裡加入serviceManager中

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();

    //在2.3版本中可以定義用一句話代替上面的代碼:

    TestService::publishAndJoinThreadPool();
    return 0;
}

BinderService中定義如下:
    static void publishAndJoinThreadPool() {
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm(defaultServiceManager());
        sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }

這裡定義的是跨進程的C/S結構,所以分為本地服務端BnTest及客戶端BpTest,為隱藏性Bp與Bn的定義與實現都入在BnTest.cpp中。
BnXX代表服務端,Bp代碼客戶端

頭文件ITest.h定義如下:
#define ANDROID_ITEST_H
#ifndef ANDROID_ITEST_H
class ITest: public IInterface
{
protected:
enum
{
TEST_GETTEST = 0,
TEST_SETTEST,
};
public:
DECLARE_META_INTERFACE(Test); //聲明重要宏定義
//定義純虛函數
virtual void getTest() = 0;
virtual void setTest() = 0;
};

//BnTest 聲明
class BnTest: public BnInterface<ITest>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

// —————————————————————————-

 

}; // namespace android

#endif // ANDROID_ITEST_H

接口實現ITest.cpp
namespace android {

//BpTest實現
class BpTest : public BpInterface<ITest>
{
public:
    BpTest(const sp<IBinder>& impl)
        : BpInterface<ITest>(impl)
    {
    }
   
    virtual void getTest()
    {
    Parcel data,reply;
    data.writeInterfaceToken(ITest::getInterfaceDescriptor());
   
    //TODO… 使用類似的writeXXX函數
    remote()->transact(TEST_GETTEST,data,&reply);
    int ret = reply.readXXX();
    return ;
    }
   
    virtual void setTest()
    {
    Parcel data,reply;
    data.writeInterfaceToken(ITest::getInterfaceDescriptor());
   
    //TODO… 使用類死的writeXXX函數
    remote()->transact(TEST_SETTEST,data,&reply);
    int ret = reply.readXXX();
    return ;
    }
};

//BnTest實現
//重要的一個定義實現
IMPLEMENT_META_INTERFACE(Test, "android.test.ITest");

status_t BnTest::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code){
case TEST_GETTEST:{
CHECK_INTERFACE(ITest, data, reply);
//TODO… setTest()
}break;
case TEST_GETTEST:{
CHECK_INTERFACE(ITest, data, reply);
//TODO… getTest()
}break;
default:
break;
}
}

// ———————————————————————-
}

從上面所述,很多代碼都基本上是一致的形式,隻是往其中添加上不同的處理代碼而已,重要的是利用Parcel對象進行序列化。

後面講講客戶端和服務端如何實現及調用情況:

客戶端如何調用:

static sp<ITest> getTestSerivce()
{
    sp<IBinder> binder;
    static sp<ITest> sTestManager = NULL;
   
    if(sTestManager != NULL)
    return sTestManager;
   
    sp<IServiceManager> sm = defaultServiceManager();
    do {
        binder = sm->getService(String16("test.service"));
        if (binder == 0) {
            LOGW("TestService not published, waiting…");
            usleep(500000); // 0.5 s
        }
    } while(binder == 0);

if(sTestManager == NULL){
sTestManager = interface_cast<ITest>(binder);
}

return sTestManager;
}

利用getTestSerivce函數獲取到客戶端管理器句柄,然後利用sTestManager->setTest/getTest調用
這是一種常用的客戶端訪問service的函數實現方法。

服務端實現:
class TestService:
public BinderService<TestService>, //2.3 存在,而2.2版本實現instantiate()函數
        public BnTest,
        protected Thread
{
public:
static void instantiate();
static char const* getServiceName() { return "test.service"; }

//服務端實現接口函數
virtual void getTest() ;
virtual void setTest() ;
};

void TestService::instantiate() {
    defaultServiceManager()->addService(
            String16("test.service"), new TestService());
}

2.3版本如此做法,在BinderService類中做瞭此事情:
class BinderService
{
public:
    static status_t publish() {
        sp<IServiceManager> sm(defaultServiceManager());
        return sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
    }
    static void instantiate() { publish(); }

};

ok,跨進程的C/S結構代碼框架就是這樣子瞭,比較明瞭。

 

    //在2.3版本中可以定義TestService::

摘自 andyhuabing的專欄

發佈留言