Android系统硬件访问服务框架分析

 

怎么实现硬件访问服务
1、JNI和HAL
com_andorid_server_ledService.cpp (JNI文件注册JNI本地方法:供app应用程序调用)
hal_led.c (C库:具体操作硬件接口函数实现)
2、修改onload.cpp 调用

com_andorid_server_ledService.cpp 中实现的函数register_andorid_server_ledService
3、修改systemServer.java
    LedService ledservice = new ledService();

    ServiceManager.addService( "led",ledservice );
4、LedService.java 调用本地方法实现硬件操作
5、ILEDServivce.java 给app使用
 

1、先来实现接口文件 ILEDService.java ,给app提供接口,aidl 文件,安卓接口定义语言
参考 android-5.0.2\frameworks\base\core\java\android\os\IVibratorService.aidl
ILedService.aidl

package android.os;
/** {@hide} */
interface ILedService
{
        int ledCtrl(int which, int status);
}

对于LED来说,提供给应用程序的只有一个控制接口,对于打开和关闭app不需要关心。
修改 android-5.0.2\frameworks\base\andorid.mk 仿照 IVibratorService.aidl 添加 ILedService.aidl
mmm . 编译,mmm 命令无法执行的话先执行 . setenv
ILedService.java 生成在 out 目录
ILedService.java 声明了app能够调用的接口函数ledCtrl,这个接口函数需要在 LedService 类中实现

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: frameworks/base/./core/java/android/os/ILedService.aidl
 */
package android.os;
/** {@hide} */
public interface ILedService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements android.os.ILedService
{
private static final java.lang.String DESCRIPTOR = "android.os.ILedService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an android.os.ILedService interface,
 * generating a proxy if needed.
 */
public static android.os.ILedService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.ILedService))) {
return ((android.os.ILedService)iin);
}
return new android.os.ILedService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_ledCtrl:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
int _result = this.ledCtrl(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements android.os.ILedService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int ledCtrl(int which, int status) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(which);
_data.writeInt(status);
mRemote.transact(Stub.TRANSACTION_ledCtrl, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_ledCtrl = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public int ledCtrl(int which, int status) throws android.os.RemoteException;
}

aidl文件编码

添加ILedService.aidl文件

mmm编译生成ILedService.java文件

APP如何使用ILedService提供的本地方法

ILedService iLedService = null;    // 定义ILedService 类

// 获取服务

iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));

iLedService.ledCtrl( 0 , 1 ); // 调用接口

 

2、实现 LedService 类
ILedService.java 提供接口,那么接口函数在哪里实现?在LedService.java
既然是个java文件,那么它必然无法直接调用硬件,还是需要通过JNI来访问硬件,JNI文件在 com_andorid_server_ledService.cpp
参考:vibratorService.java (frameworks\base\services\core\java\com\android\server)

package com.android.server;
import android.os.ILedService;

public class LedService extends ILedService.Stub {
    private static final String TAG = "LedService";

	/* call native c function to access hardware */
	public int ledCtrl(int which, int status) throws android.os.RemoteException
	{
		return native_ledCtrl(which, status);
	}

	public LedService() {
		native_ledOpen();
	}

	public static native int native_ledOpen();
	public static native void native_ledClose();
	public static native int native_ledCtrl(int which, int status);
}

将 LedService.java 拷贝到 frameworks\base\services\core\java\com\android\server
无需 .mk 文件,frameworks\base\services\core\Android.mk 默认包含了全部 java 文件
如何注册 Service 到 ServerManger ?
参考:SystemServer.java (frameworks\base\services\java\com\android\server)

Slog.i(TAG, "Led Service");
ServiceManager.addService("led", new LedService());

注册之后,app 就可以使用 ILedService 接口

参考: systemVibrator.java (frameworks\base\core\java\android\os)

public class SystemVibrator extends Vibrator {
    private static final String TAG = "Vibrator";
    private final IVibratorService mService;
    private final Binder mToken = new Binder();
    //应用程序中看到 ServiceManager.getService("xxx")就应该知道它使用的是硬件访问服务
    public SystemVibrator() {
        mService = IVibratorService.Stub.asInterface(
                ServiceManager.getService("vibrator"));//向上转型成接口
    }
    public SystemVibrator(Context context) {
        super(context);
        mService = IVibratorService.Stub.asInterface(
                ServiceManager.getService("vibrator"));
    }
    public boolean hasVibrator() {
        if (mService == null) {
            Log.w(TAG, "Failed to vibrate; no vibrator service.");
            return false;
        }
        try {
            return mService.hasVibrator();//调用提供的接口函数
        } catch (RemoteException e) {
        }
        return false;
    }
    ...

3、实现 JNI 文件 com_android_server_ledService.cpp
注册本地方法,供 LedService 使用
参考:com_android_server_VibratorService.cpp (frameworks\base\services\core\jni)

#define LOG_TAG "LedService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware_legacy/vibrator.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <android/log.h>  /* liblog */
static jint fd;
jint ledOpen(JNIEnv *env, jobject cls)
{
        ALOGI("native ledOpen");
        printf("%s\n",__func__);
        fd = open("/dev/leds", O_RDWR);
        if (fd < 0)
        {
                ALOGI("native ledOpen error");
        }
        return fd;
}
void ledClose(JNIEnv *env, jobject cls, jint a, jint b)
{
        close(fd);
        ALOGI("native ledClose");
}
jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
        int ret = ioctl(fd, status, which);
        ALOGI("native ledCtrl which %d static %d", which, status);
        return ret;
}
namespace android
{
        static JNINativeMethod method_table[] = {
                { "native_Open", "()I", (void*)ledOpen },
                { "native_Close", "()V", (void*)ledClose },
                { "native_Ctrl", "(II)I", (void*)ledCtrl }
        };
        int register_android_server_LedService(JNIEnv *env)
        {
                return jniRegisterNativeMethods(env, "com/android/server/LedService",
                                method_table, NELEM(method_table));
        }
};

修改Onload.cpp (frameworks\base\services\core\jni)

int register_android_server_LedService(JNIEnv *env);
register_android_server_LedService(env);

将 com_andorid_server_LedService.cpp 拷贝到 frameworks\base\services\core\jni 目录

修改 frameworks\base\services\core\jni\Android.mk 添加

 $(LOCAL_REL_DIR)/com_android_server_LedService.cpp \

共计修改了两个 mk 文件
frameworks\base\services\core\Android.mk
frameworks\base\services\core\jni\Android.mk

编译:
mmm frameworks/base/services
make snod
./gen-img.sh
 

4、写 app 程序

import android.os.ILedService;    //导入接口
private ILedService ledService = null; 
ledService = ILedService.Stub.asInterface(ServiceManager.getService("led"));//获得ledService
ledService.ledCtrl(i, 0);         //使用ledService

android studio 不能直接使用 ILedService 接口,需要导入 classes.jar

5、JNI 再分层,实现一个 so 文件,供 JNI 调用
JNI 文件和 so 文件均为 C 实现,在分层的好处时,更改硬件操作只需要更改 so 文件,无需重新编译 system,
此外,有一定的保密作用。
那么,JNI 如何调用 so 文件?和 C 语言调用库文件大概是一样的吧,dlopen ,但是安卓肯定会有自己的封装。
分层之后,
JNI 向上提供本地函数,向下加载 hal so 文件
HAL 负责访问硬件驱动程序

安卓中使用如下函数加载 so 文件,传入一个字符串,获得一个 hw_module_t 结构体

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    /* 查找 so 文件是否存在 */
found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status;
    void *handle;
    struct hw_module_t *hmi;
    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }
    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;//"HMI"
    /* 根据 动态链接库 操作句柄(handle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址 ,在此获取名为 "HMI" 的结构体 */
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
    hmi->dso = handle;
    /* success */
    status = 0;
    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }
    *pHmi = hmi;//hw_module_t
    return status;
}

如何使用,参考:com_android_server_lights_LightsService.cpp (frameworks\base\services\core\jni)

libhardware/include/hardware/lights.h:31:#define LIGHTS_HARDWARE_MODULE_ID "lights"
static jlong init_native(JNIEnv *env, jobject clazz)
{
    int err;
    hw_module_t* module;
    Devices* devices;
    
    devices = (Devices*)malloc(sizeof(Devices));
    err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    if (err == 0) {
        devices->lights[LIGHT_INDEX_BACKLIGHT]
                = get_device(module, LIGHT_ID_BACKLIGHT);
        devices->lights[LIGHT_INDEX_KEYBOARD]
                = get_device(module, LIGHT_ID_KEYBOARD);
        ...
    } else {
        memset(devices, 0, sizeof(Devices));
    }
    return (jlong)devices;
}
static light_device_t* get_device(hw_module_t* module, char const* name)
{
    int err;
    hw_device_t* device;//这里直接定义成 light_device_t 更好理解
    err = module->methods->open(module, name, &device);//hw_module_t -> hw_device_t
    if (err == 0) {
        return (light_device_t*)device;//把device地址处的东东转换为具体的结构体
    } else {
        return NULL;
    }
}
struct light_device_t {
    struct hw_device_t common;
    /**
     * Set the provided lights to the provided values.
     *
     * Returns: 0 on succes, error code on failure.
     */
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);
};

device 如何使用?

static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr,
        jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
{
    Devices* devices = (Devices*)ptr;
    light_state_t state;
    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
        return ;
    }
    memset(&state, 0, sizeof(light_state_t));
    state.color = colorARGB;
    state.flashMode = flashMode;
    state.flashOnMS = onMS;
    state.flashOffMS = offMS;
    state.brightnessMode = brightnessMode;
    {
        ALOGD_IF_SLOW(50, "Excessive delay setting light");
        devices->lights[light]->set_light(devices->lights[light], &state);//so 文件中实现
    }
}

参考:/hardware/libhardware/modules/vibrator/vibrator.c

typedef struct vibrator_device {
    struct hw_device_t common;
    int (*vibrator_on)(struct vibrator_device* vibradev, unsigned int timeout_ms);
    int (*vibrator_off)(struct vibrator_device* vibradev);
} vibrator_device_t;
#include <hardware/vibrator.h>
#include <hardware/hardware.h>
#include <cutils/log.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
static const char THE_DEVICE[] = "/sys/class/timed_output/vibrator/enable";
static int vibra_exists() {
    int fd;
    return 1;
}
static int sendit(unsigned int timeout_ms)
{
    return ret;
}
static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
{
    /* constant on, up to maximum allowed time */
    return sendit(timeout_ms);
}
static int vibra_off(vibrator_device_t* vibradev __unused)
{
    return sendit(0);
}
static int vibra_close(hw_device_t *device)
{
    free(device);
    return 0;
}
static int vibra_open(const hw_module_t* module, const char* id __unused,
                      hw_device_t** device __unused) {
    if (!vibra_exists()) {
        ALOGE("Vibrator device does not exist. Cannot start vibrator");
        return -ENODEV;
    }
    vibrator_device_t *vibradev = calloc(1, sizeof(vibrator_device_t));
    if (!vibradev) {
        ALOGE("Can not allocate memory for the vibrator device");
        return -ENOMEM;
    }
    vibradev->common.tag = HARDWARE_DEVICE_TAG;
    vibradev->common.module = (hw_module_t *) module;// hw_module_t 就这点用?
    vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);
    vibradev->common.close = vibra_close;
    vibradev->vibrator_on = vibra_on;
    vibradev->vibrator_off = vibra_off;
    *device = (hw_device_t *) vibradev;
    return 0;
}
/*===========================================================================*/
/* Default vibrator HW module interface definition                           */
/*===========================================================================*/
static struct hw_module_methods_t vibrator_module_methods = {
    .open = vibra_open,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .id = VIBRATOR_HARDWARE_MODULE_ID,
    .name = "Default vibrator HAL",  //hw_get_module("led",...)
    .methods = &vibrator_module_methods,
};

 ----------------------------------------------------------------------------------------------------------------------
LED 实例:

#ifndef _HARDWARE_LED_HAL_H
#define _HARDWARE_LED_HAL_H
#include <hardware/hardware.h>
__BEGIN_DECLS
struct led_device;
typedef struct led_device {
    struct hw_device_t common;
    int  (*led_open)(struct led_device* leddev);
    void (*led_close)(struct led_device* leddev);
    int  (*led_ctrl)(struct led_device* leddev, int which, int status);
} led_device_t;
__END_DECLS
#endif  // _HARDWARE_VIBRATOR_H

JNI:

#define LOG_TAG "LedService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <stdio.h>
#include <hardware/led_hal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <android/log.h>  /* liblog */
static jint fd;
static hw_module_t* module;
static led_device_t* leddev;
static led_device_t* get_device(hw_module_t* module, char const* name)
{
    int err;
    hw_device_t* device;
    err = module->methods->open(module, name, &device);
    if (err == 0) {
        return (led_device_t*)device;
    } else {
        return NULL;
    }
}
jint ledOpen(JNIEnv *env, jobject cls)
{
	ALOGI("native ledOpen");
    	if (hw_get_module("led", (hw_module_t const**)&module) == 0)
	{
		leddev = get_device(module, NULL);
	}
	leddev->led_open(leddev);
	return fd;
}
void ledClose(JNIEnv *env, jobject cls, jint a, jint b)
{
	leddev->led_close(leddev);
	ALOGI("native ledClose");
}
jint ledCtrl(JNIEnv *env, jobject cls, jint which, jint status)
{
	leddev->led_ctrl(leddev, status, which);
	ALOGI("native ledCtrl which %d static %d", which, status);
	return 0;
}
namespace android
{
	static JNINativeMethod method_table[] = {
		{ "native_Open", "()I", (void*)ledOpen },
		{ "native_Close", "()V", (void*)ledClose },
		{ "native_Ctrl", "(II)I", (void*)ledCtrl }
	};
	int register_android_server_LedService(JNIEnv *env)
	{
		return jniRegisterNativeMethods(env, "com/android/server/LedService",
				method_table, NELEM(method_table));
	}
};
#include <hardware/hardware.h>
#include <hardware/led_hal.h>
#include <cutils/log.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <android/log.h>  /* liblog */
static int fd;
static int led_open(struct led_device* leddev)
{
	ALOGI("led_open");
	fd = open("/dev/leds", O_RDWR);
	if (fd < 0)
	{
		ALOGI("led_open error");
	}
	return fd;
}
static int led_close(struct hw_device_t* device)
{
	ALOGI("led_close");
	close(fd);
	return 0;
}
static int led_ctrl(struct led_device* leddev, int status, int which)
{
	int ret = ioctl(fd, status, which);
	ALOGI("led_ctrl which %d static %d", which, status);
	return ret;
}
static int led_device_open(const hw_module_t* module, const char* id __unused,
                      hw_device_t** device __unused) {
    led_device_t *leddev = calloc(1, sizeof(led_device_t));
    if (!leddev) {
        ALOGE("Can not allocate memory for the led device");
        return -ENOMEM;
    }
    leddev->common.close = led_close;
    leddev->led_open = led_open;
    leddev->led_ctrl = led_ctrl;
    *device = (hw_device_t *) leddev;
    return 0;
}
static struct hw_module_methods_t led_module_methods = {
    .open = led_device_open,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .name = "led",
    .methods = &led_module_methods,
};

 

 

参考链接:https://blog.csdn.net/lizuobin2/article/details/73009142

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章