本篇在Windows环境下开发Android Native服务#第一篇:使用AOSP生成Clion工程基础上,继续扩展为Android Native服务。
2.1 编写代码
删掉clion_demo中的clion_demo.cpp,添加如下文件:
HelloNativeService.h
#ifndef ANDROID_10_HELLONATIVESERVICE_H
#define ANDROID_10_HELLONATIVESERVICE_H
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
using namespace android;
class HelloNativeService: public BBinder {
public:
HelloNativeService();
static int instantiate();
virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
};
#endif //ANDROID_10_HELLONATIVESERVICE_H
HelloNativeService.cpp
#include <android/log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "HelloNativeService.h"
#define LOG_TAG "HelloNativeService"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
enum {
CMD_SAY_HELLO = 1,
CMD_CAL_SUM = 2
};
static void sayHello(const char *name) {
LOGD("hello %s from HelloNativeService", name);
}
static int sum(int a, int b) {
return a + b;
}
HelloNativeService::HelloNativeService() {
LOGD("HelloNativeService created");
}
int HelloNativeService::instantiate() {
int r = defaultServiceManager()->addService(String16("HelloNativeService"),new HelloNativeService());
LOGD("add HelloNativeService r = %d", r);
return r;
}
status_t HelloNativeService::onTransact(uint32_t code, const Parcel &request, Parcel *reply, uint32_t flag) {
switch (code) {
case CMD_SAY_HELLO:
sayHello(request.readCString());
return NO_ERROR;
case CMD_CAL_SUM:
int a = request.readInt32();
int b = request.readInt32();
reply->writeInt32(sum(a, b));
return NO_ERROR;
}
return BBinder::onTransact(code, request, reply, flag);
}
Main.cpp
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "HelloNativeService.h"
using namespace android;
int main(int argc, char *argv[]) {
sp<ProcessState> proc(ProcessState::self());
HelloNativeService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
测试程序:
HelloNativeTest.cpp
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <stdio.h>
using namespace android;
enum {
CMD_SAY_HELLO = 1,
CMD_CAL_SUM = 2
};
static sp<IBinder> service;
static void test_sayHello() {
Parcel request, reply;
request.writeCString("qiushao");
service->transact(CMD_SAY_HELLO, request, &reply);
}
static void test_calSum() {
Parcel request, reply;
request.writeInt32(2);
request.writeInt32(3);
service->transact(CMD_CAL_SUM, request, &reply);
int sum = reply.readInt32();
printf("sum of 2 + 3 = %d\n", sum);
}
int main () {
service = defaultServiceManager()->getService(String16("HelloNativeService"));
test_sayHello();
test_calSum();
return 0;
}
Android.bp
cc_binary {
name: "HelloNativeService",
srcs: ["main.cpp", "HelloNativeService.cpp"],
shared_libs: [
"libbase",
"libprocessgroup",
"libcutils",
"libutils",
"libbinder",
"liblog",
"libziparchive",
],
}
cc_binary {
name: "HelloNativeTest",
srcs: ["HelloNativeTest.cpp"],
shared_libs: [
"liblog",
"libcutils",
"libutils",
"libbinder",
],
}
这里我们创建一个Hello服务,主要内容在HelloNativeService.cpp中,并编写main.cpp将这个服务运行起来。还编写了测试程序HelloNativeTest.cpp。 修改CMakefiles.txt,将源文件导入进来:
读者可以自行在Clion修改代码内容,如果导入了新的库,可以参看篇一,重新生成CMakefiles.txt以更新头文件路径。
2.2 配置开机自动运行
在clion_demo中添加rc文件:
vendor.xxxx.clionDemo@1.0-service.rc
service HelloNativeService /system/bin/HelloNativeService
class core
user root
group root
seclabel u:r:HelloNativeService:s0
修改Android.bp,导入rc文件:
这里rc文件最后会导入到
/{system,vendor,odm}/etc/init/*.rc
下,因为没有在Andorid.bp中做特殊配置,默认就放到system分区下了。之后开机init进程将会运行该脚本启动服务。
2.3 配置selinux规则
这里选择直接在device\xxx\common\sepolicy
目录下配置selinux规则,创建clionDemo目录。并在device\xxx\common\product.mk
中配置加入:
BOARD_VENDOR_SEPOLICY_DIRS += device/xxx/common/sepolicy/clionDemo
导入sepolicy规则。
file_contexts
/system/bin/HelloNativeService u:object_r:HelloNativeService_exec:s0
service_contexts
HelloNativeService u:object_r:HelloNativeService_service:s0
helloNativeService.te
type HelloNativeService, domain;
typeattribute HelloNativeService coredomain;
type HelloNativeService_exec, system_file_type, exec_type, file_type;
binder_use(HelloNativeService)
init_daemon_domain(HelloNativeService)
allow HelloNativeService HelloNativeService_service:service_manager { add find };
service.te
type HelloNativeService_service, service_manager_type;
2.4 编译运行
在/vendro/clion_demo
中创建product.mk文件,并在device\xxx\common\product.mk
中配置加入:
$(call inherit-product-if-exists, vendor/clion_demo/product.mk)
导入我们的product.mk文件
product.mk
PRODUCT_PACKAGES += HelloNativeService HelloNativeTest
之后编译镜像即可。可以看到在编译后的system/bin
目录下已经有我们的服务和测试程序了:
system/etc/init目录下也有了rc文件:
烧录运行后,查看服务列表,可以看到我们的 HelloNativeService 已经在运行状态了。然后执行 HelloNativeTest,服务端正确返回了计算结果。查看一下 logcat, HelloNativeService 也正确收到了 HelloNativeTest 传递过来的数据。
作为Native Service其实这里可以使用hal服务,其实是一个道理,不过就不用我们自己编写HelloNativeService.cpp
中的HelloNativeService::onTransact
这种模板函数了,这一点可以参考Android Java/C++引用hal接口开发