为 Android添加底层核心服务

    技术2022-05-20  38

     

    本文转自:http://blog.csdn.net/belyxiong/archive/2010/09/10/5875993.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());

                    }

    本文来自博客,转载请标明出处:http://blog.csdn.net/belyxiong/archive/2010/09/10/5875993.aspx


    最新回复(0)