Android N 添加系统服务Freg

来源:互联网 发布:怎么写好网络小说知乎 编辑:程序博客网 时间:2024/06/05 14:31

本文是基于《Android系统源代码情景分析》第二章 硬件抽象层
代码是在MTK N版本上编译通过的,如果是原生代码,相关路径会有所变化。
老罗的代码是Android 2.3的,驱动代码在最新的N版本上已经编译不过了,所以重新修改了下,同时添加selinux权限,并实现了一个fregd守护进程。
原始的代码是FregService是通过JNI->HAL->驱动来读写/dev/freg的,新加了fregd守护进程,这样FregService就可以通过binder->HAL->驱动来读写/dev/freg了。
fregd是仿造system/core/fingerprintd写的。
源码下载
以下是新添加的selinux权限,具体语法可查看老罗相关的文章

device/mediatek/common/sepolicy/basic/device.te

type freg_device, dev_type;

device/mediatek/common/sepolicy/basic/file_contexts

/dev/freg(/.*)? u:object_r:freg_device:s0/system/bin/fregd  u:object_r:fregd_exec:s0

device/mediatek/common/sepolicy/basic/service.te

type freg_service, service_manager_type;type fregd_service, service_manager_type;

device/mediatek/common/sepolicy/basic/service_contexts

freg    u:object_r:freg_service:s0android.os.IFregDaemon    u:object_r:fregd_service:s0

device/mediatek/common/sepolicy/basic/freg.te

#java服务FregService需要添加的权限#for FregServiceallow system_server freg_device:chr_file {read write};allow system_server freg_device:chr_file {open};allow system_server freg_service:service_manager {add};allow untrusted_app freg_service:service_manager {find};allow system_app freg_service:service_manager {find};#domain 切换#init_daemon_domain(mediaserver)#这个是一个TE操作宏, 简单来说就是当init fork子进程执行fregd_exec 这个类型的执行档时, 其domain从init切换到fregd.#守护进程fregd需要添加的权限#for fregdtype fregd, domain;type fregd_exec, exec_type, file_type;init_daemon_domain(fregd)#system/bin/fregd  u:object_r:fregd_exec:s0allow fregd freg_device:chr_file {open read write};allow fregd fregd_service:service_manager {add};allow fregd servicemanager:binder {call transfer};allow system_server fregd_service:service_manager {find};allow system_server fregd:binder {call};allow servicemanager fregd:dir {search};allow servicemanager fregd:process {getattr};allow servicemanager fregd:file {read open};

创建一个fregd可执行文件,在init.rc里启动,会添加一个名为android.os.IFregDaemon的系统服务。

IFregDaemon.h

#ifndef IFREG_DAEMON_H_1#define IFREG_DAEMON_H_1#include <binder/IInterface.h>#include <binder/Parcel.h>namespace android {/** Abstract base class for native implementation of FregService.** Note: This must be kept manually in sync with IFregDaemon.aidl*/class IFregDaemon : public IInterface, public IBinder::DeathRecipient {    public:        enum {           SET_VAL = IBinder::FIRST_CALL_TRANSACTION + 0,           GET_VAL = IBinder::FIRST_CALL_TRANSACTION + 1,           OPEN_HAL = IBinder::FIRST_CALL_TRANSACTION + 2,           CLOSE_HAL = IBinder::FIRST_CALL_TRANSACTION + 3,           INIT = IBinder::FIRST_CALL_TRANSACTION + 4,        };        IFregDaemon() { }        virtual ~IFregDaemon() { }        virtual const android::String16& getInterfaceDescriptor() const;        // Binder interface methods        virtual void init() = 0;        virtual int32_t getVal() = 0;        virtual int32_t setVal(int32_t val) = 0;        virtual int64_t openHal() = 0;        virtual int32_t closeHal() = 0;        // DECLARE_META_INTERFACE - C++ client interface not needed        static const android::String16 descriptor;};class BnFregDaemon: public BnInterface<IFregDaemon> {    public:       virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,               uint32_t flags = 0);};} // namespace android#endif // IFREG_DAEMON_H_

IFregDaemon.cpp

#include <inttypes.h>#include <binder/IPCThreadState.h>#include <binder/IServiceManager.h>#include <binder/PermissionCache.h>#include <utils/String16.h>#include <utils/Looper.h>#include <hardware/hardware.h>#include <hardware/freg.h>#include "IFregDaemon.h"namespace android {const android::String16IFregDaemon::descriptor("android.os.IFregDaemon");const android::String16&IFregDaemon::getInterfaceDescriptor() const {    return IFregDaemon::descriptor;}status_t BnFregDaemon::onTransact(uint32_t code, const Parcel& data, Parcel* reply,        uint32_t flags) {    switch(code) {        case SET_VAL: {            CHECK_INTERFACE(IFregDaemon, data, reply);            const int32_t val = data.readInt32();            const int32_t ret = setVal(val);            reply->writeNoException();            reply->writeInt32(ret);            return NO_ERROR;        };        case GET_VAL: {            CHECK_INTERFACE(IFregDaemon, data, reply);            const int32_t ret = getVal();            reply->writeNoException();            reply->writeInt32(ret);            return NO_ERROR;        }        case OPEN_HAL: {            CHECK_INTERFACE(IFregDaemon, data, reply);            const int64_t ret = openHal();            reply->writeNoException();            reply->writeInt64(ret);            return NO_ERROR;        }        case CLOSE_HAL: {            CHECK_INTERFACE(IFregDaemon, data, reply);            const int32_t ret = closeHal();            reply->writeNoException();            reply->writeInt32(ret);            return NO_ERROR;        }        case INIT: {            CHECK_INTERFACE(IFregDaemon, data, reply);            init();            reply->writeNoException();            return NO_ERROR;        }        default:            return BBinder::onTransact(code, data, reply, flags);    }};}; // namespace android

FregDaemonProxy.h

#ifndef FREG_DAEMON_PROXY_H_#define FREG_DAEMON_PROXY_H_#include "IFregDaemon.h"namespace android {class FregDaemonProxy : public BnFregDaemon {    public:        static FregDaemonProxy* getInstance() {            if (sInstance == NULL) {                sInstance = new FregDaemonProxy();            }            return sInstance;        }        // These reflect binder methods.        virtual void init();        virtual int32_t getVal();        virtual int32_t setVal(int32_t val);        virtual int64_t openHal();        virtual int32_t closeHal();    private:        FregDaemonProxy();        virtual ~FregDaemonProxy();        static FregDaemonProxy* sInstance;        freg_module_t const* mModule;        freg_device_t* mDevice;        void binderDied(const wp<IBinder>& who);};} // namespace android#endif // FREG_DAEMON_PROXY_H_

FregDaemonProxy.cpp

#define LOG_TAG "fregd"#include <binder/IServiceManager.h>#include <hardware/hardware.h>#include <hardware/freg.h>#include <utils/Log.h>#include "FregDaemonProxy.h"namespace android {FregDaemonProxy* FregDaemonProxy::sInstance = NULL;FregDaemonProxy::FregDaemonProxy() : mModule(NULL), mDevice(NULL) {}FregDaemonProxy::~FregDaemonProxy() {    closeHal();}void FregDaemonProxy::init() {}int32_t FregDaemonProxy::getVal() {    if(!mDevice) {        ALOGE("Device freg is not open.");        return 0;    }    int val = 0;    mDevice->get_val(mDevice, &val);    ALOGI("Get value %d from device freg.", val);    return val;}int32_t FregDaemonProxy::setVal(int32_t value){    if(!mDevice) {        ALOGE("Device freg is not open.");        return -1;    }    int val = value;    ALOGI("Set value %d to device freg.", val);    mDevice->set_val(mDevice, val);    return 0;}int64_t FregDaemonProxy::openHal() {    const hw_module_t *hw_module = NULL;    ALOGI("Initializing HAL stub freg......");    /*加载硬件抽象层模块freg*/    if(hw_get_module(FREG_HARDWARE_MODULE_ID, &hw_module) == 0) {        ALOGI("Device freg found.");        mModule = reinterpret_cast<const freg_module_t*>(hw_module);        /*打开虚拟硬件设备freg*/        hw_device_t *device = NULL;        if (mModule->common.methods->open(hw_module, FREG_HARDWARE_DEVICE_ID, &device) == 0) {            ALOGI("Device freg is open.");            mDevice = reinterpret_cast<freg_device_t*>(device);            return reinterpret_cast<int64_t>(mDevice);        }        ALOGE("Failed to open device freg.");        return 0;    }    ALOGE("Failed to get HAL stub freg.");    return 0;}int32_t FregDaemonProxy::closeHal() {    ALOG(LOG_VERBOSE, LOG_TAG, "nativeCloseHal()\n");    mDevice = NULL;    return 0;}void FregDaemonProxy::binderDied(const wp<IBinder>& who) {    ALOGD("binder died");    int err;    if (0 != (err = closeHal())) {        ALOGE("Can't close fingerprint device, error: %d", err);    }    if (who != NULL) {}}}

fregd.cpp

#define LOG_TAG "fregd"#include <cutils/log.h>#include <utils/Log.h>#include <binder/IPCThreadState.h>#include <binder/IServiceManager.h>#include <binder/PermissionCache.h>#include <utils/String16.h>#include <hardware/hardware.h>#include <hardware/freg.h>#include "FregDaemonProxy.h"int main() {    ALOGI("Starting " LOG_TAG);    android::sp<android::IServiceManager> serviceManager = android::defaultServiceManager();    android::sp<android::FregDaemonProxy> proxy =            android::FregDaemonProxy::getInstance();    android::status_t ret = serviceManager->addService(            android::FregDaemonProxy::descriptor, proxy);    if (ret != android::OK) {        ALOGE("Couldn't register " LOG_TAG " binder service!");        return -1;    }    /*     * We're the only thread in existence, so we're just going to process     * Binder transaction as a single-threaded program.     */    android::IPCThreadState::self()->joinThreadPool();    ALOGI("Done");    return 0;}

Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_CFLAGS := -Wall -Wextra -Werror -WunusedLOCAL_SRC_FILES := \    FregDaemonProxy.cpp \    IFregDaemon.cpp \    fregd.cppLOCAL_MODULE := fregdLOCAL_SHARED_LIBRARIES := \    libbinder \    liblog \    libhardware \    libutilsinclude $(BUILD_EXECUTABLE)

添加到init.rc里,debug.fregd属性用于debug时手动开启和停止服务

device/mediatek/mt6735/init.mt6735.rcservice fregd /system/bin/fregd    class main    user system    group systemon property:debug.fregd=0    stop fregdon property:debug.fregd=1    start fregd

添加对应的framework接口,顺序必须与IFregDaemon.h里的枚举一致。
core/java/android/os/IFregDaemon.aidl

package android.os;/** * Communication channel from FregService to FregDaemon (fregd) * @hide */interface IFregDaemon {    int setVal(int val);    int getVal();    long openHal();    int closeHal();    void init();}

在FregService添加对应的方法
frameworks/base/services/java/com/android/server/FregService

    private IFregDaemon mDaemon;    private static final String FREGD = "android.os.IFregDaemon";    private IFregDaemon getFregDaemon() {        if (mDaemon == null) {            mDaemon = IFregDaemon.Stub.asInterface(ServiceManager.getService(FREGD));            if (mDaemon != null) {                try {                    mHalDeviceId = mDaemon.openHal();                    if (mHalDeviceId == 0) {                        Slog.w(TAG, "Failed to open Freg HAL!");                        mDaemon = null;                    }                } catch (RemoteException e) {                    Slog.e(TAG, "Failed to open fingeprintd HAL", e);                    mDaemon = null; // try again later!                }            } else {                Slog.w(TAG, "Freg service not available");            }        }        return mDaemon;    }    public int getVal_fregd() {        IFregDaemon daemon = getFregDaemon();        if (daemon == null) {            Slog.w(TAG, "getVal_fregd: no fregd!");            return 0;        }        try {            return daemon.getVal();        } catch (RemoteException e) {            Slog.e(TAG, "getVal_fregd failed", e);        }        return 0;    }    public int setVal_fregd(int val){        IFregDaemon daemon = getFregDaemon();        if (daemon == null) {            Slog.w(TAG, "setVal_fregd: no fregd!");            return 0;        }        try {            return daemon.setVal(val);        } catch (RemoteException e) {            Slog.e(TAG, "setVal_fregd failed", e);        }        return 0;    }

添加到编译系统里去
frameworks/base/Android.mk

LOCAL_SRC_FILES += \    core/java/android/os/IFregService.aidl \    core/java/android/os/IFregDaemon.aidl \

这样FregSevice就可以通过fregd去读写驱动了。

推荐文章
Binder系列8—如何使用Binder