閱讀552 返回首頁    go 阿裏雲 go 技術社區[雲棲]


為 Android 添加 Java 層服務

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

                }


Java層服務顧名思義即為從 Java層提供的服務,它與 C++層的服務不同之處在於其服務進程的運行由係統( ServiceManager)統一維護。在文件 frameworks /base /services /java /com /android /server /SystemServer.java 中我們可以看到以下代碼:

AlarmManagerService alarm = new AlarmManagerService (context );

ServiceManager .addService (Context .ALARM_SERVICE , alarm );

 

這個操作在係統啟動時完成,由 ServiceManager 負責創建服務進程並運行之。所以我們要做的事就是實現一個 java 服務,並將其添加到這裏並由係統運行起來,以下是具體實現步驟:

 

 

實現自己的 java層 service

1.       在目錄

frameworks/base/core/java/android/os中增加自己的 AIDL文件用來申明服務:

BelyService.aidl:

package android.os;

interface IBelyService {

        /**

        *

        */

        int calculateSqu(int value);

}

2.       在目錄

frameworks/base/services/java/com/android/server增加 service的實現文件:

BelyService.java:

package com.android.server;

import android.content.Context;

import android.os.IBelyService;

public class BelyService extends IBelyService.Stub {

        public BelyService(Context context){

                super();

        }

        public int calculateSqu(int val){

                return val*val;

        }

}

 

3.       將 java服務添加到 ServiceManager中:

BelyService bs = new BelyService(context);

ServiceManager.addService("BelyService", bs);

 

自此,重新編譯 Android並運行,我們所創建的服務即可訪問,下麵是演示如何調用:

同樣在 package/apps下任意創建一個應用,調用服務的方法如下:

import android.os.ServiceManager;

import android.os.IBelyService;

IBelyService bs = IBelyService.Stub.asInterface(ServiceManager.getService("BelyService"));

int ret = bs.calculateSqu(9);

 

上麵我們使用的是 Android內部的方法來獲取服務,當然也可以使用公開的 API: context.getSystemService來獲取。


最後更新:2017-04-02 22:16:35

  上一篇:go 添加一個係統服務sytem service
  下一篇:go Android添加一個係統service