写blog的时候,发现跳章了,HAL硬件抽象层都没有写就到JNI了,这里补回来。
1、添加HAL头文件
进入到 android-4.0.4_r1.2/hardware/libhardware/include/hardware 目录,创建 ttt.h 文件:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2/hardware/libhardware/include/hardware# gedit ttt.h
文件内容如下:
#ifndef ANDROID_TTT_INTERFACE_H
#define ANDROID_TTT_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
// 定义模块ID
#define HELLO_HARDWARE_MODULE_ID "ttt"
// 硬件模块结构体
struct ttt_module_t{
struct hw_module_t common;
};
// hardware interface struct
struct ttt_device_t{
struct hw_device_t common;
int fd;
int(*set_val)(struct ttt_device_t* dev, int val);
int(*get_val)(struct ttt_device_t* dev, int* val);
};
__END_DECLS
#endif
这里按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。
2、实现HAL
进入android-4.0.4_r1.2/hardware/libhardware/modules 目录,创建 ttt 目录:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2/hardware/libhardware/modules# mkdir ttt
进入到新创建的ttt目录下面,并创建 ttt.c 文件:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2/hardware/libhardware/modules/ttt# gedit ttt.c
其内容如下:
#define LOG_TAG "TTTStub"
#include <hardware/hardware.h>
#include <hardware/ttt.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#define DEVICE_NAME "/dev/ttt"
#define MODULE_NAME "TTT"
#define MODULE_AUTHOR "brantyou@qq.com"
// open/close device interface
static int ttt_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int ttt_device_close(struct hw_device_t* device);
// device interfaces
static int ttt_set_val(struct ttt_device_t* dev, int val);
static int ttt_get_val(struct ttt_device_t* dev, int* val);
// module methods
static struct hw_module_methods_t ttt_module_methods = {
open: ttt_device_open
};
// module variables
const struct ttt_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: HELLO_HARDWARE_MODULE_ID,
name: MODULE_NAME,
author: MODULE_AUTHOR,
methods: &ttt_module_methods,
}
};
// * device set value interface
static int ttt_set_val(struct ttt_device_t* dev, int val)
{
LOGI("TTT Stub: set value %d to device.", val);
write(dev->fd, &val, sizeof(val));
return 0;
}
// * device get value interface
static int ttt_get_val(struct ttt_device_t* dev, int* val)
{
if(!val){
LOGE("TTT Stub: error val pointer.");
return -EFAULT;
}
read(dev->fd, val, sizeof(*val));
LOGI("TTT Stub: get value %d from device.", *val);
return 0;
}
// * close device interface
static int ttt_device_close(struct hw_device_t* device)
{
struct ttt_device_t* ttt_device = (struct ttt_device_t*)device;
if(ttt_device){
close(ttt_device->fd);
free(ttt_device);
}
return 0;
}
// * open device interface
static int ttt_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device)
{
struct ttt_device_t* dev;
dev = (struct ttt_device_t*)malloc( sizeof(struct ttt_device_t) );
if(!dev){
LOGE("TTT stub: failed to alloc space");
return -EFAULT;
}
memset(dev, 0, sizeof(struct ttt_device_t));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (hw_module_t*)module;
dev->common.close = ttt_device_close;
dev->set_val = ttt_set_val;
dev->get_val = ttt_get_val;
if( (dev->fd = open(DEVICE_NAME, O_RDWR)) == -1){
LOGE("TTT Stub: failed to open /dev/ttt -- %s.", strerror(errno));
free(dev);
return -EFAULT;
}
*device = &(dev->common);
LOGI("TTT Stub: open /dev/ttt successfully.");
return 0;
}
在该目录下创建对应的Android.mk文件:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2/hardware/libhardware/modules/ttt# gedit Android.mk
其内容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := ttt.c
LOCAL_MODULE := ttt.default
include $(BUILD_SHARED_LIBRARY)
3、添加权限
由于设备文件是在内核驱动里面通过 device_create 创建的,而 device_create 创建的设备文件默认只有 root 用户
可读写,而 ttt_device_open 一般是由上层APP来调用的,这些 APP 一般不具有 root 权限,这时候就有可能导致打开设备文件失败,提示类似于:
Permission denied.
解决办法是类似 linux 的udev 规则,
进入到 android-4.0.4_r1.2/system/core/rootdir 目录,打开 uenentd.rc 文件:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2/system/core/rootdir# gedit ueventd.rc
在里面添加一句:
/dev/ttt 0666 root root
4、开始编译
执行命令如下:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2# mmm hardware/libhardware/modules/ttt
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=full_smdkv210
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=IMM76I
============================================
make:进入目录'/home/brantyou/workspace/android-4.0.4_r1.2'
target thumb C: ttt.default <= hardware/libhardware/modules/ttt/ttt.c
target SharedLib: ttt.default (out/target/product/smdkv210/obj/SHARED_LIBRARIES/ttt.default_intermediates/LINKED/ttt.default.so)
target Symbolic: ttt.default (out/target/product/smdkv210/symbols/system/lib/hw/ttt.default.so)
target Strip: ttt.default (out/target/product/smdkv210/obj/lib/ttt.default.so)
Install: out/target/product/smdkv210/system/lib/hw/ttt.default.so
make:离开目录“/home/brantyou/workspace/android-4.0.4_r1.2”
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2#
重新打包system.img:
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2# make snod
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=full_smdkv210
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=IMM76I
============================================
build/core/Makefile:25: 警告:覆盖关于目标“out/target/product/smdkv210/system/bin/pppd”的命令
build/core/base_rules.mk:523: 警告:忽略关于目标“out/target/product/smdkv210/system/bin/pppd”的旧命令
make snod: ignoring dependencies
Target system fs image: out/target/product/smdkv210/system.img
out/target/product/smdkv210/system.img total size is 150853824
root@brantyou-ubuntu:~/workspace/android-4.0.4_r1.2#
到此,HAL层的就编写完了,下一篇就是编写对应的JNI接口了。