本篇在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接口开发