Android N 添加系统服务Freg

本文是基于《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:s0
android.os.IFregDaemon    u:object_r:fregd_service:s0

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

#java服务FregService需要添加的权限
#for FregService
allow 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 fregd
type fregd, domain;
type fregd_exec, exec_type, file_type;
init_daemon_domain(fregd)

#system/bin/fregd  u:object_r:fregd_exec:s0

allow 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::String16
IFregDaemon::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 -Wunused
LOCAL_SRC_FILES := \
    FregDaemonProxy.cpp \
    IFregDaemon.cpp \
    fregd.cpp
LOCAL_MODULE := fregd
LOCAL_SHARED_LIBRARIES := \
    libbinder \
    liblog \
    libhardware \
    libutils
include $(BUILD_EXECUTABLE)

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

device/mediatek/mt6735/init.mt6735.rc
service fregd /system/bin/fregd
    class main
    user system
    group system

on property:debug.fregd=0
    stop fregd

on 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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值