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服务已经全部完成,在板子上测试一下,发现能正常运行。