1、Android 的核心框架技術之 1: 如何撰寫第一個核心服務如何撰寫自己的第一個核心服務呢?by 高煥堂*高煥堂 的最新課程消息*1. 要點: 核心服務通常在獨立的進程(Process)裡執行。 必須提供 IBinder 介面,讓應用程式可以進行跨進程的綁定(Binding)和呼叫。 因為共用,所以必須確保多線裎安全(Thread-safe)。 以 C+類別定義,誕生其物件,透過 SM 之協助,將該物件參考值傳給IServiceManager:addService()函數,就加入到 Binder Driver 裡了。 應用程式可透過 SM 之協助而遠距綁定該核心服務,此時 SM 會回傳 IB
2、inder 介面給應用程式。 應用程式可透過 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 #include #in
3、clude #include namespace android class AddService : public BBindermutable Mutex mLock;int32_t mNextConnId;public:static int instantiate();AddService();virtual AddService();virtual status_t onTransact(uint32_t, const Parcel; /namespace#endif/*- AddService.cpp 實作檔 -*/ AddService.cpp#include “AddServic
4、e.h“#include #include 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 = %dn“, r);return r;AddService:AddSe
5、rvice() LOGV(“AddService created“);mNextConnId = 1;pthread_key_create(AddService:AddService() pthread_key_delete(sigbuskey);LOGV(“AddService destroyed“);status_t AddService:onTransact(uint32_t code, const Parcelint num = data.readInt32();num = num + 1000;reply-writeInt32(num);return NO_ERROR; break;
6、default:return BBinder:onTransact(code, data, reply, flags); /namespace/*- Make 檔 -*/Android.mkLOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= AddService.cppLOCAL_C_INCLUDES := $(JNI_H_INCLUDE)LOCAL_SHARED_LIBRARIES := libutilsLOCAL_PRELINK_MODULE := falseLOCAL_MODULE := libAddincl
7、ude $(BUILD_SHARED_LIBRARY)執行上述 Android.mk 檔,就產出 libAdd.so 檔案了。Step-2:以 C+撰寫一個可獨立執行的 addserver.cpp 程式,它的用途是:誕生一個AddService 類別之物件,然後將該物件參考存入 Binder Driver 裡。其內容為:/*- addserver.cpp -*/#include #include #include #include #include #include #include #include #include “/libadd/AddService.h“/#include using
8、 namespace android;int main(int argc, char* argv)sp proc(ProcessState:self();sp sm = defaultServiceManager();LOGI(“ServiceManager: %p“, sm.get();AddService:instantiate();ProcessState:self()-startThreadPool();IPCThreadState:self()-joinThreadPool();編譯並連結此 addserver.cpp,產出 addserver 可執行程式。Step-3:上述兩個步驟
9、分別產出了 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()-addServ
10、ice(String16(“guilh.add“), new AddService();LOGE(“AddService r = %dn“, r);return r;其先執行到 new AddServer(),就誕生一個 AddServer 類別之物件;接著,呼叫defaultServiceManager()函數取得 SM 的 IServiceManager 介面,再呼叫IServiceManager:addServer()將該物件參考存入 Binder Driver 裡,如下圖所示:3. 入門級範例:寫個 Add 類別來使用 AddService 核心服務剛才已經成功地將 AddServic
11、e 服務加入到 Binder Driver 裡了。現在,茲寫個 C+應用類別來繫結(Bind)此核心服務。Step-5:以 C+撰寫 Add 類別,其完整程式碼為:/*- Add.h -*/#ifndef ANDROID_GUILH_ADD_H#define ANDROID_GUILH_ADD_Hnamespace android class Add public:void setN(int n);private:static const void getAddService(); /namespace#endif / ANDROID_GUILH_ADD_H/*- Add.cpp -*/#in
12、clude #include #include “Add.h“namespace android sp 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, return;const void Add:getAddService()sp sm = defaultServiceManager()
13、;binder = sm-getService(String16(“guilh.add“);LOGE(“Add:getAddService %pn“,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)安全性,才能提供穩定可靠的核心服務。