Windows环境下开发Android Native服务#第二篇:开发Android Native Service

本篇在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,将源文件导入进来:


image.png

读者可以自行在Clion修改代码内容,如果导入了新的库,可以参看篇一,重新生成CMakefiles.txt以更新头文件路径。

2.2 配置开机自动运行

在clion_demo中添加rc文件:

image.png

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文件:

image.png

这里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规则。


image.png

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文件


image.png

product.mk

PRODUCT_PACKAGES += HelloNativeService HelloNativeTest

之后编译镜像即可。可以看到在编译后的system/bin目录下已经有我们的服务和测试程序了:

image.png

system/etc/init目录下也有了rc文件:

image.png

烧录运行后,查看服务列表,可以看到我们的 HelloNativeService 已经在运行状态了。然后执行 HelloNativeTest,服务端正确返回了计算结果。查看一下 logcat, HelloNativeService 也正确收到了 HelloNativeTest 传递过来的数据。

image.png

作为Native Service其实这里可以使用hal服务,其实是一个道理,不过就不用我们自己编写HelloNativeService.cpp中的HelloNativeService::onTransact这种模板函数了,这一点可以参考Android Java/C++引用hal接口开发

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容