【安卓framework实战】实现一个安卓native服务

本文介绍了如何实现一个安卓native服务。
需求: 在native framework层实现一个服务接受云控配置,并执行云控命令。
已有条件:系统接受到云控配置会发送特定action的广播并将信息包含在intent中,我们只需要接受此广播并完成我们的逻辑即可。

一、预先分析

在开始写代码之前,做一些功能点大致的分析如下:
1:在java framework需要一个广播接收器,接受传来的广播,此广播接收器需要在开机时就注册。根据安卓开机流程,我选择在system_server启动AMS后,注册此Receiver。为了不卡住,此Receiver需要运行在自己的线程,要有自己的messageQueue。
接受到广播之后,通过binder调用到native服务执行native的逻辑。
2:native服务需要在开机时启动,根据安卓开机流程,我可能需要修改init.rc的开机脚本,并配置一些SELinux规则以成功在开机时将我的服务注册到servicemanager中。

二、Native服务代码

仿照audioflinger的做法,实现自己的native服务。
native服务的文件组织如下,具体路径为framework/base/dynamicopt/dynamicopt-service/:
在这里插入图片描述
其中,TestClient是在native测试native服务的客户端。.bp和.mk文件是用来编译代码的。

1:IDynaOption.h,这是一个接口

//
// Created by zxs on 21-6-10.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <android/log.h>
#include <cutils/properties.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <android/log.h>


using namespace android;

#ifndef ANDROID_IDYNAOPT_H
#define ANDROID_IDYNAOPT_H
namespace android {
class IDynaOptService: public IInterface {
    public:
        DECLARE_META_INTERFACE(DynaOptService);
        virtual void shellExecuteDirectly(String16 s) = 0;
};

enum{
    SHELL_EXECUTE_DIRECTLY = IBinder::FIRST_CALL_TRANSACTION,
};

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

}// namespace android
#endif //ANDROID_IDYNAOPT_H

2:IDynaOption.cpp

//
// Created by zxs on 21-6-10.
//
#include "IDynaOption.h"
namespace android {
class BpDynaOptService: public BpInterface<IDynaOptService> {
    public:
        BpDynaOptService(const sp<IBinder>& impl)
            :BpInterface<IDynaOptService>(impl) {
        }

    virtual void shellExecuteDirectly(String16 s) {
        Parcel data, reply;
        data.writeInterfaceToken(IDynaOptService::getInterfaceDescriptor());
        data.writeString16(s);
        remote()-> transact(SHELL_EXECUTE_DIRECTLY, data, &reply);
    }
};

IMPLEMENT_META_INTERFACE(DynaOptService, "android.dynaOptServer.IDynaOptService");

status_t BnDynaOptService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
    switch (code) {
        case SHELL_EXECUTE_DIRECTLY: {
            CHECK_INTERFACE(IDynaOption, data, reply);
            shellExecuteDirectly(data.readString16());
            reply->writeInt32(100);
            if(flags) {
                return 0;
            }
            return NO_ERROR;
            break;
        }
        default:
            break;
    }
    return NO_ERROR;
}
}// namespace android

3:DynaOptService.cpp

//
// Created by zxs on 21-6-8.
//

#include "IDynaOption.h"
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <cutils/log.h>
#include <binder/ProcessState.h>
#include <sys/stat.h>
#include <stdio.h>

namespace android {
class DynaOptService: public BnDynaOptService {
    public:
        DynaOptService();
        virtual ~DynaOptService();
        void shellExecuteDirectly(String16 s);
};

DynaOptService::DynaOptService() {
    ALOGI("DynaOptService created.");
}

DynaOptService::~DynaOptService() {
    ALOGI("DynaOptService destroyed.");
}


void DynaOptService::shellExecuteDirectly(String16 s) {
    ALOGI("DynaOptService shellExecuteDirectly.");
    std::string shell = String8(s).string();
    if(shell.empty()) {
        ALOGI("DynaOptService: shell is empty.");
        return;
    }
    system(String8(s));
}
}// namespace android

int main() {
    sp<ProcessState> proc(ProcessState::self());
    defaultServiceManager()->addService(String16("service.dynaoptservice"), new DynaOptService());
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

4:Android.bp

cc_library_static {
    name: "libzouserver",

    cflags: [
        "-Wno-unused-parameter",
    ],

    srcs: [
        "DynaOptService.cpp",
        "IDynaOption.cpp",
    ],

    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
    ],

    export_include_dirs: ["."],
}

cc_binary {
    name: "dynaopt",
    srcs: [
        "DynaOptService.cpp",
    ],

    cflags: [
        "-Wno-unused-parameter",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "libbinder",
        "liblog",
    ],
    static_libs: ["libzouserver"],

    init_rc: ["DynaOptService.rc"],
}

cc_binary {
    name: "zouclient",
    srcs: [
        "TestClient.cpp",
        "IDynaOption.cpp",
    ],
    shared_libs: [
        "libcutils",
        "libutils",
        "libbinder",
        "liblog",
    ],
}

5:TestClient.cpp

//
// Created by zxs on 21-6-10.
//

#include "IDynaOption.h"
using namespace android;

int main()
{
	sp <IBinder> binder = defaultServiceManager()->getService(String16("service.dynaoptservice"));
	sp<IDynaOptService> cs = interface_cast <android::IDynaOptService> (binder);
	ALOGI("DynaOptService :Hello Native service\n");
	//std::vector<String16> vec = {"/system/bin/logcat -b all -d -f /data/syslog/test20210611.txt","/system/bin/logcat -b all -d -f /data/syslog/good20210611.txt"};
	cs->shellExecuteDirectly(String16("/system/bin/logcat -b all -d -f /data/syslog/test20210611.txt"));
	return 0;
}

6:Android.mk

LOCAL_PATH := $(call my-dir)

include $(call first-makefiles-under,$(LOCAL_PATH))

7:DynaOptService.rc

这个是rc脚本,安卓开机的时候会执行此命令运行服务的。

service dynaopt_server /system/bin/dynaopt
    class core

8:common.mk

在device/xiaomi/sm"XXXX"-common/common.mk中增加以下,让自己的代码可以被编译,并在开机的时候可以启动自己的服务。
这里的“dynaopt”写自己在android.bp中编译出来的二进制文件的名字就行。我的话写的就是“dynaopt”。

# dynaoptservice
PRODUCT_PACKAGES += \
    dynaopt

三、解决selinux问题

这个可以看我的上一篇文档自己解决一下。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值