编写android native Service

Android Service是四大组件之一,app级的service大部分是java语言实现的,通过aidl一键生成+业务逻辑处理代码,实现比较简单。还有一种service是native service,即本地服务,由cpp编写,framework中的media,audio都是这种native service。下面记录一下怎么一步一步实现native service。
首先看一下目录结构,在vendor下创建目录: vendor/rex/nativeservicetest,并分别建立3个子目录:

  • librexservice (服务端逻辑处理,处理客户端请求,最终编译成一个shared_library)
  • rexserver (服务端,用来注册和启动service,一个server可以对应多个service,最终编译成一个bin)
  • democlient (客户端,通过binder调用服务端接口,以bin的形式发布)
    目录结构

Step 1 编写服务librexservice

首先要定义一个接口IRexPlayerService继承IInterface,此接口明确服务端能提供什么样的服务,假设我们有一个addSampleData的接口,传入int value实现加法功能。
注意服务端和客户端都需要继承IRexPlayerService, 服务端创建BnRexPlayerService (类似JAVA aidl自动生成的stub),客户端创建BpRexPlayerService。
注意DECLARE_META_INTERFACE宏是android预定好,方便我们定义接口的。
IRexPlayerService.h:

#ifndef IREXPLAYERSERVICE_H
#define IREXPLAYERSERVICE_H
#include <binder/IInterface.h>

namespace android
{
static const char* REX_PLAYER_SERVICE = "rex.player";

class Parcel;

class IRexPlayerService : public IInterface
{
public:
    DECLARE_META_INTERFACE(RexPlayerService);

    virtual void addSampleData(uint32_t value) = 0;
};

class BnRexPlayerService : public BnInterface<IRexPlayerService>
{
public:
    virtual status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags = 0);
};

}; //namespace android

#endif

IRexPlayerService.cpp:

  • 定义了一个枚举ADD_SAMPLE_DATA用来标识addSampleData接口
  • 定义BpRexPlayerService(客户端使用),继承模板类BpInterface,注意BpRexPlayerService中实现的addSampleData方法,即打包数据,通过binder发送给服务端。
  • 实现BnRexPlayerService(服务端使用)的onTransact方法,即服务端接收到ADD_SAMPLE_DATA后调用纯虚接口addSampleData(uint32_t value)完成处理。
    注意使用了IMPLEMENT_META_INTERFACE(RexPlayerService,“android.rex.IRexPlayerService”)宏,和头文件的DECLARE宏配对使用,方便定义接口。
#define LOG_NDEBUG 0
#define LOG_TAG "IRexPlayerService"
#include <utils/Log.h>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <binder/Parcel.h>
#include <stdint.h>

#include "IRexPlayerService.h"

namespace android {
    enum{
        CREATE = IBinder::FIRST_CALL_TRANSACTION,
        ADD_SAMPLE_DATA
    };

class BpRexPlayerService : public BpInterface<IRexPlayerService>
{
public:
    explicit BpRexPlayerService(const sp<IBinder>& impl)
        : BpInterface<IRexPlayerService>(impl)
    {
        ALOGD("create BpRexPlayerService \n");
    }

    virtual void addSampleData(uint32_t value)
    {
        ALOGD("BpRexPlayerService: addSampleData:%d \n",value);
        Parcel data, reply;
        data.writeInterfaceToken(IRexPlayerService::getInterfaceDescriptor());
        data.writeInt32(value);
        remote()->transact(ADD_SAMPLE_DATA, data, &reply);
    }
};

IMPLEMENT_META_INTERFACE(RexPlayerService,"android.rex.IRexPlayerService");

// ----------------------------------------------------------------------
status_t BnRexPlayerService::onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
{
    ALOGD("BnInterface: onTransact, code = %d ", code);
    switch (code)
    {
    case ADD_SAMPLE_DATA:
    {
        CHECK_INTERFACE(IRexPlayerService, data, reply);
        uint32_t value = data.readInt32();
        addSampleData(value);
        return NO_ERROR;
    }   
    break;
    default:
        return BBinder::onTransact(code, data, reply, flags);
        break;
    };
}

};  //namespace android

接下来定义服务端的真正实现类:RexPlayerService,继承自BnRexPlayerService。在BnRexPlayerService中的onTransact方法中调用的纯虚接口addSampleData(uint32_t value),实际是由类RexPlayerService实现的
RexPlayerService.h

#ifndef REXPLAYERSERVICE_H
#define REXPLAYERSERVICE_H

#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>

#include "IRexPlayerService.h"

namespace android {
class RexPlayerService : public BnRexPlayerService
{
public:
    RexPlayerService();
    virtual ~RexPlayerService();

    virtual void addSampleData(uint32_t value);
private:
    uint32_t mCurrentVal;
    Mutex mLock;
};

};//namespace android

#endif

RexPlayerService.cpp
RexPlayerService实现比较简单,就是对成员变量mCurrentVal的一个自增操作。

#define LOG_NDEBUG 0
#define LOG_TAG "RexPlayerService"
#include <utils/Log.h>

#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "IRexPlayerService.h"
#include "RexPlayerService.h"

namespace android {

RexPlayerService::RexPlayerService() : mCurrentVal(0),
                                        mLock("RexPlayerServiceLock")
{
    ALOGD("RexPlayerService start \n");
}

RexPlayerService::~RexPlayerService()
{
    ALOGD("RexPlayerService destroyed \n");
}

void RexPlayerService::addSampleData(uint32_t value)
{
    Mutex::Autolock lock(mLock);
    mCurrentVal += value;
    ALOGD("RexPlayerService: addSampleData, mCurrentVal is %d \n",mCurrentVal);
}

};//namespace android

Android.bp:

cc_library_shared {
    name: "librexplayerservice",
    cflags: [
        "-Werror",
        "-Wno-error=deprecated-declarations",
        "-Wall",
    ],
    srcs: [
        "RexPlayerService.cpp",
        "IRexPlayerService.cpp",
    ],
    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
        "libstagefright_foundation",
    ],
    local_include_dirs: ["include"],
}

自此服务端的代码编写完成,可以尝试mm一下,会在out\target\product\XXX\system\lib以及 lib64下生成librexplayerservice.so

Step 2 编写Server

server是一个可执行文件,它向serviceManager注册并启动RexPlayerService。
注意addService传入的服务名为 IRexPlayerService.h定义的 “rex.player”
main_rexplayerserver.cpp:

#define LOG_TAG "RexPlayerServerMain"
#define LOG_NDEBUG 0

#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cutils/properties.h>
#include <fcntl.h>
#include <utils/Log.h>

#include "RexPlayerService.h"

using namespace android;

int main(int argc __unused, char **argv __unused)
{
    sp<ProcessState> proc(ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();

    ALOGI("RexPlayerServerMain: sm: %p", sm.get());
    sp<RexPlayerService> mService = new RexPlayerService();
    sm->addService(String16(REX_PLAYER_SERVICE),mService);

    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
}

Android.bp:

cc_binary {
    name: "rexplayerserver",
    init_rc: ["rexplayerserver.rc"],
    srcs: [
        "main_rexplayerserver.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "liblog",
        "libbinder",
        "librexplayerservice",
    ],
    cflags: [
        "-Werror",
        "-Wno-error=deprecated-declarations",
        "-Wno-unused-parameter",
        "-Wall",
    ],
    include_dirs: [
        "vendor/rex/nativeservicetest/librexservice/include",
    ],
}

rexplayerserver.rc

service rexplayerserver /system/bin/rexplayerserver
    class main
    user root
    group system media
on property:on property:sys.boot_completed=1
    start rexplayerserver

让server开机自启动还需要在 device/qcom/sepolicy中添加向应的te文件,这里不做详细描述。

Step 3 编写客户端调用服务

DemoClient.h

#ifndef DEMOCLIENT_H
#define DEMOCLIENT_H

#include <utils/RefBase.h>
#include "IRexPlayerService.h"

namespace android{
class DemoClient : public RefBase
{
public:
    DemoClient();
    ~DemoClient();
    status_t attachPlayerService();
    void addSampleData(uint32_t value);
private:
   sp<IRexPlayerService> mService;
};
};

#endif //namespace android

DemoClient.cpp

#define LOG_TAG "DemoClient"
#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include "DemoClient.h"


namespace android{
enum {
    EN_RET_OK = 0,
    EN_RET_NG = 1,
};

DemoClient::DemoClient():mService(0)
{
    ALOGD("Construct DemoClient");
}

status_t DemoClient::attachPlayerService()
{
    sp<IServiceManager> sm = defaultServiceManager();
    mService = IRexPlayerService::asInterface(sm->getService(String16("rex.player")));
    if(mService != NULL)
    {
        ALOGD("get native service : %p success",mService.get());
        return EN_RET_OK;
    }
    ALOGE("can not get IRexPlayerService");
    return EN_RET_NG;
}

DemoClient::~DemoClient()
{
    ALOGD("Destroy DemoClient");
}

void DemoClient::addSampleData(uint32_t value)
{
    if(mService != NULL)
    {
        ALOGD("addSampleData : %d", value);
        mService->addSampleData(value);
    }
    else 
    {
        ALOGE("addSampleData but mService is NULL!");
    }
}

};

int main(int argc, char const *argv[])
{
    using namespace android;
    sp<DemoClient> client = new DemoClient();
    client->attachPlayerService();
    client->addSampleData(15);
    return 0;
}


Android.bp

cc_binary {
    name: "democlient",
    srcs: [
        "DemoClient.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "liblog",
        "libbinder",
        "librexplayerservice",
    ],
    cflags: [
        "-Werror",
        "-Wno-error=deprecated-declarations",
        "-Wno-unused-parameter",
        "-Wall",
    ],
    include_dirs: [
        "vendor/rex/nativeservicetest/democlient",
        "vendor/rex/nativeservicetest/librexservice/include",
    ],
}

至此 native服务已经全部完成,在板子上测试一下,发现能正常运行。
运行结果

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值