爲 Android添加底層核心服務(一)

zhuanzi:  http://blog.csdn.net/leilu2008/archive/2011/03/29/6286779.aspx

 

1.     爲什麼要寫底層核心服務呢?
         因爲底層核心服務是 Android框架裏最接近 Linux/Driver的部分。爲了充分發揮硬件設備的差異化特性,核心服務是讓上層 Java應用程序來使用 Driver/HW Device 特色的重要管道。例如 Media、 Telephone等底層硬件。

       在開機過程中,就可以啓動核心服務(漢字輸入法服務等),讓衆多應用程序來共同使用。

由於共用,所以能有效降低 Java應用程序的大小( Size)。

2.     核心服務與 Java 層的 Service有何區別和關係?
       Android具有兩層服務

             --Java層 SDK-based Service

             --C++層的 Code Service

 

3. 編寫自己的核心服務( C++ 層)
1). 要點
      核心服務通常在獨立的進程( Process )裏執行。

      必須提供 IBinder 接口,讓應用程序可以進行跨進程的綁定( Binding )和調用。

      因爲共用,所以必須確保多線程安全( Thread-safe )。

使用 C++ 來實現,並調用 IServiceManager::addService() 函數添加到系統的 Binder Driver 裏。

上層應用程序通過 ServiceManager 獲取該服務。

上層應用程序通過 IBinder::transact() 函數來與核心服進行數據交互。

2). 添加服務
下面詳細介紹如何添加一個底層服務到系統中,假設服務名爲 AddService ,其用途是對傳入的參數加上 1000 ,並返回結果。

服務實現
      進入 android 源碼 的目錄 frameworks/base ,在該目錄下建立自己的目錄,假設爲 addservice ,再在這個目錄中建立兩個子目錄 addserver 和 libaddservice , addserver 用於存放服務的啓動文件,其最終的生成爲可執行文件,在系統啓動的時候運行, libaddservice 用於存放服務的實現文件,最終會生成動態鏈接庫,有 addserver 調用。

 

首先,服務的實現文件包括兩個文件,   AddService.h 和 AddService.cpp ,

以下是 AddService.h :

#ifndef ANDROID_GUILH_ADD_SERVICE_H

#define ANDROID_GUILH_ADD_SERVICE_H

 

#include <utils/RefBase.h>

#include <binder/IInterface.h>

#include <binder/Parcel.h>

#include <utils/threads.h>

 

namespace android {

        class AddService : public BBinder{// 從 BBinder 派生,實現本地接口

 

                public:

                static int instantiate();

                AddService();

                virtual ~AddService();

                virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);

        };

}; //namespace

#endif

然後是服務的實現文件 AddService.cpp :

#include "AddService.h"

#include <binder/IServiceManager.h>

#include <binder/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());// 這裏主要是把 //AddSerice 這個服務添加到 Binder Driver 中服務名爲 guilh.add

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");

}

// 這個是服務具體的本地實現,功能實現都應該放在這裏面,通過傳入執行代碼( code ) // 的不同來執行不同的操作,上層隱射爲不同的 api 。

status_t AddService::onTransact(

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

switch(code) {

case 0: {// 根據 code 的不同執行不同的操作

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

 

以下是編譯服務的 Android.mk ,和上面的 cpp 放在一起。

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= /

AddService.cpp

LOCAL_C_INCLUDES := /

$(JNI_H_INCLUDE)

LOCAL_SHARED_LIBRARIES :=     /

        libcutils             /

        libutils              /

        libbinder             /

        libandroid_runtime

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE := libAdd

include $(BUILD_SHARED_LIBRARY)   #這一行表示編譯爲動態庫

在命令行中退出到 android/目錄級 加載編譯環境 . build/envsetup.sh

然後 lunch。

然後在 cd  /android/frameworks/base/addservice/ libaddservice/ 目錄 輸入 mm

之後在 out 目錄產出 libAdd.so 文件。

在此 完成核心服務第一步。

 

服務進程實現
                進入到 cd  /android/frameworks/base/addservice/addserver/ 目錄

增加一個文件 addserver.cpp ,文件內容如下:

#include <sys/types.h>

#include <unistd.h>

#include <grp.h>

#include <binder/IPCThreadState.h>

#include <binder/ProcessState.h>

#include <binder/IServiceManager.h>

#include <utils/Log.h>

#include <private/android_filesystem_config.h>

#include "../libaddservice/AddService.h"

//#include <libadd/AddService.h>

using namespace android;

int main(int argc, char** argv)

{

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

sp<IServiceManager> sm = defaultServiceManager();//取得 ServiceManager

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

AddService::instantiate();//把自己添加到 ServiceManager中

ProcessState::self()->startThreadPool();//啓動緩衝池

IPCThreadState::self()->joinThreadPool();//這裏是把服務添加到 Binder閉合循環進程中

}

以上爲底層服務的標準操作。

下面是這個服務 makefile:

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= /

        addserver.cpp

LOCAL_SHARED_LIBRARIES := /

        libAdd /

        libutils /

        libbinder

LOCAL_MODULE:= addserver

include $(BUILD_EXECUTABLE)//編譯爲可執行文件

退出後當前目錄執行 mm即可在 out目錄的 system/bin下產出 addserver可執行文件。

實現服務進程開機自動運行
進入到 /android/system/core/rootdir/目錄中有個 init.rc文件

vi init.rc

在 service中添加

service addservice    /system/bin/addserver    //將 /system/bin/addserver作爲一個服務啓動,服務的名稱爲 addservice(這個不重要)。

最後退出到 android/目錄下執行全編譯:

輸入 . build/envsetup.sh

Lunch

Make

完成之後

Emulator打開模擬器

打開另一個 shell終端 輸入 adb shell    進入模擬器模式      如果 adbshell系統提示沒有發現該命令 就在 android/out/host/linux-x86/bin/中輸入   ./adb shell  

在輸入 ps  查看進程   找到是否有 addserver進程

如果有就成功一半。

 

測試我們的服務

隨便在 android/packages/apps 中 建立一個簡單的應用程序,

這裏可以直接在 eclipse 中建立好工程 拷貝到 android/packages/apps 中,然後爲應用添加一個 Android.mk 文件,可以從其他應用中拷貝來修改。

在應用程序中測試服務的代碼:

    private void test(){

                try{

                        IBinder binder = ServiceManager.getService("guilh.add");// 取得服務

                        Parcel data = Parcel.obtain();

                        Parcel reply = Parcel.obtain();

                        if(binder == null)

                                Log.d(TAG,"failed to get service");

                        data.writeInt(Process.myPid());// 固定操作

                        data.writeInt(100);// 傳入參數

                        binder.transact(0, data, reply, 0);// 執行遠程調用

                        Log.d(TAG,"result="+reply.readInt());// 驗證結果

                }catch(Exception e){

                         Log.d(TAG,e.toString());

                }

(以上部分資料來源於高煥堂 android 核心服務,歡迎提出您的意見及建議)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章