怎么实现硬件访问服务
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