现在的位置: 首页 > 综合 > 正文

如何撰寫自己的第一個核心服務呢?

2018年06月10日 ⁄ 综合 ⁄ 共 4840字 ⁄ 字号 评论关闭

1. 要點:

l          

核心服務通常在獨立的進程
(Process)
裡執行。

l          

必須提供
IBinder
介面,讓應用程式可以進行跨進程的綁定
(Binding)
和呼叫。

l          

因為共用,所以必須確保多線裎安全
(Thread-safe)

l          


C++
類別定義,誕生其物件,透過
SM
之協助,將該物件參考值傳給
IServiceManager::addService()
函數,就加入到
Binder Driver
裡了。

l          

應用程式可透過
SM
之協助而遠距綁定該核心服務,此時
SM
會回傳
IBinder
介面給應用程式。

l          

應用程式可透過
IBinder::transact()
函數來與核心服務互傳資料。

 

2.
入門級範例:將
AddService
核心服務加入
Binder Driver

此範例功能為簡單的整數加法
(Add)
運算,此核心服務命名為
AddService

Step-1


C++
撰寫
AddService
類別,其完整程式碼為:

 

/*--- AddService.h
定義檔
---*/

//AddService.h

#ifndef ANDROID_GUILH_ADD_SERVICE_H

#define ANDROID_GUILH_ADD_SERVICE_H

#include <utils.h>

#include <utils/RefBase.h>

#include <utils/IInterface.h>

#include <utils/Parcel.h>

 

namespace android {

class AddService : public BBinder{

     mutable     Mutex     mLock;

                 int32_t   mNextConnId;

 public:

     static  int instantiate();

AddService();

     virtual ~AddService();

     virtual status_t onTransact(

             uint32_t, const Parcel&, Parcel*, uint32_t);

}}; //namespace

#endif

 

/*--- AddService.cpp
實作檔
---*/

// AddService.cpp

#include "AddService.h"

#include <utils/IServiceManager.h>

#include <utils/IPCThreadState.h>

 

namespace android {

static struct sigaction oldact;

static pthread_key_t sigbuskey;

 

int AddService::instantiate() {

               LOGE("AddService instantiate");

      int r = defaultServiceManager()->addService(

                   String16("guilh.add"), new AddService());

               LOGE("AddService r = %d/n", r);

return r;

}

 

AddService::AddService()

   {  LOGV("AddService created");

      mNextConnId = 1;

      pthread_key_create(&sigbuskey, NULL);

   }

 

AddService::~AddService()

   {  pthread_key_delete(sigbuskey);

        LOGV("AddService destroyed");

   }

 

status_t AddService::onTransact(

        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){

        switch(code) {

           case 0: {

              pid_t pid = data.readInt32();

              int num = data.readInt32();

              num =  num + 1000;

              reply->writeInt32(num);

                 return NO_ERROR;

        } break;

        default:

             return BBinder::onTransact(code, data, reply, flags);

         }

}}; //namespace

 

/*--- Make

---*/

/
/Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= /

AddService.cpp

 

LOCAL_C_INCLUDES := /

  $(JNI_H_INCLUDE)

LOCAL_SHARED_LIBRARIES := /

    libutils

 

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE := libAdd

 

include $(BUILD_SHARED_LIBRARY)

 

執行上述
Android.mk
檔,就產出
libAdd.so
檔案了。

 

Step-2


C++
撰寫一個可獨立執行的
addserver.cpp
程式,它的用途是:誕生一個
AddService
類別之物件,然後將該物件參考存入
Binder Driver
裡。其內容為:

 

/*--- addserver.cpp ---*/

#include <sys/types.h>

#include <unistd.h>

#include <grp.h>

 

#include <utils/IPCThreadState.h>

#include <utils/ProcessState.h>

#include <utils/IServiceManager.h>

#include <utils/Log.h>

 

#include <private/android_filesystem_config.h>

 

#include "../libadd/AddService.h"

//#include <libadd/AddService.h>

 

using namespace android;

 

int main(int argc, char** argv)

{

    sp<ProcessState> proc(ProcessState::self());

    sp<IServiceManager> sm = defaultServiceManager();

    LOGI("ServiceManager: %p", sm.get());

    AddService::instantiate();

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

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

}

 

編譯並連結此
addserver.cpp
,產出
addserver
可執行程式。

 

Step-3

上述兩個步驟分別產出了
libAdd.so
類別庫和
addserver
可執行程式了。接著將
libAdd.so
拷貝到
Android
模擬器的
/system/lib/
裡;也把
addserver
拷貝到
/system/bin/
裡。

Step-4

執行
addserver
,其中的指令:

AddServer::instantiate();

       

就執行到
AddServer
類別的
instantiate()
函數,其內容為:

 

int AddService::instantiate() {

               LOGE("AddService instantiate");

      int r = defaultServiceManager()->addService(

                   String16("guilh.add"), new AddService());

               LOGE("AddService r = %d/n", r);

return r;

}

 

其先執行到
new AddServer()
,就誕生一個
AddServer
類別之物件;接著,呼叫
defaultServiceManager()
函數取得
SM

IServiceManager
介面,再呼叫
IServiceManager::addServer()
將該物件參考存入
Binder Driver
裡,如下圖所示:

 

   

 

3.
入門級範例:寫個
Add
類別來使用
AddService
核心服務

剛才已經成功地將
AddService
服務加入到
Binder Driver
裡了。現在,茲寫個
C++
應用類別來繫結
(Bind)
此核心服務。

Step-5


C++
撰寫
Add
類別,其完整程式碼為:

 

/*--- Add.h ---*/

#ifndef ANDROID_GUILH_ADD_H

#define ANDROID_GUILH_ADD_H

 

namespace android {

class Add {

public:

    void  setN(int n);

private:

           static const void getAddService();

};

 

}; //namespace

#endif // ANDROID_GUILH_ADD_H

 

 

/*--- Add.cpp ---*/

#include <utils/IServiceManager.h>

#include <utils/IPCThreadState.h>

#include "Add.h"

 

namespace android {

  sp<IBinder> binder;

void Add::setN(int n){

             getAddService();

      Parcel data, reply;

      data.writeInt32(getpid());

      data.writeInt32(n);

           LOGE("BpAddService::create remote()->transact()/n");

      binder->transact(0, data, &reply);

           return;

}

const void Add::getAddService(){

    sp<IServiceManager> sm = defaultServiceManager();

    binder = sm->getService(String16("guilh.add"));

   LOGE("Add::getAddService %p/n",sm.get());

    if (binder == 0) {

          LOGW("AddService not published, waiting...");

          return;

}

}

}; //namespace

 

其中的
setN()
函數呼叫
getAddService()
函數來取得
SM
的介面參考,然後要求
SM
去協助繫結到
AddService
核心服務,完成時
SM
會回傳
BpBinder
物件的
IBinder
介面參考,然後暫存於
binder
變數裡。如下圖所示:

 

 


 


 4. 後語

Add.cpp通常只是用來測試核心服務而已,你也可以撰寫JNI Native 函數來呼叫核心服務的功能,例如下圖:

 



 

此外,撰寫核心服務時,必須確保多線程
(Multi-Thread)

安全性,才能提供穩定可靠的核心服務。



抱歉!评论已关闭.