跨進程C/S native service服務編寫android
2012-02-10 11:30:18 我來講兩句 收藏 我要投稿框架
純Native的Service表示代碼都在Native層,前面的文章講到了兩個service進程經過這binder中的onTransacton進行通信,而這篇文章主要講利用C/S結構的方法,利用IInterface進行相互訪問。函數
以具體代碼爲例:ui
test.cpp :spa
using namespace android;code
int main(int argc, char** argv)對象
{接口
sp<ProcessState> proc(ProcessState::self());進程
sp<IServiceManager> sm = defaultServiceManager();ip
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的專欄