您的位置:首页 > 移动开发 > Android开发

Android N 添加系统服务Freg

2017-05-18 17:49 561 查看
本文是基于《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 f
f69a
or 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: