老罗的ANDROID之旅---硬件抽象层学习笔记

来源:互联网 发布:淘宝介入举证时间 编辑:程序博客网 时间:2024/05/19 11:47

下面是在学习老罗的ANDROID之旅hal过程中的笔记: 基本上都是从其COPY的

Android的硬件抽象层,简单来说,就是对Linux内核驱动程序的封装,向上提供接口,屏蔽低层的实现细节。也就是说,把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中,硬件抽象层运行在用户空间,而Linux内核驱动程序运行在内核空间。为什么要这样安排呢?把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现的角度来看,是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。我们知道,Linux内核源代码版权遵循GNU License,而Android源代码版权遵循Apache License,前者在发布产品时,必须公布源代码,而后者无须发布源代码。如果把对硬件支持的所有代码都放在Linux驱动层,那就意味着发布时要公开驱动程序的源代码,而公开源代码就意味着把硬件的相关参数和实现都公开了,在手机市场竞争激烈的今天,这对厂家来说,损害是非常大的。因此,Android才会想到把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来了。也正是由于这个分层的原因,Android被踢出了Linux内核主线代码树中。大家想想,Android放在内核空间的驱动程序对硬件的支持是不完整的,把Linux内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说Android是开放系统而不是开源系统的原因。

在学习Android硬件抽象层的过程中,我们将会学习如何在内核空间编写硬件驱动程序、如何在硬件抽象层中添加接口支持访问硬件、如何在系统启动时提供硬件访问服务以及 如何编写JNI使得可以通过Java接口来访问硬件,而作为中间的一个小插曲,我们还将学习一下如何在Android系统中添加一个C可执行程序来访问硬件驱动程序。


在Ubuntu上为Android系统编写Linux内核驱动程序

我的开发测试环境是ANDROID 4.2 以及 Linux3.4 ,我将相关的驱动程序放在drivers/media/video/sunxi_csi/device 下面,主要是为了测试的方便:
hello.h  1 #ifndef _HELLO_ANDROID_H_                                                                                                         2 #define _HELLO_ANDROID_H_    3   4 #include <linux/cdev.h>  5 #include <linux/semaphore.h>  6   7 #define HELLO_DEVICE_NODE_NAME  "hello"    8 #define HELLO_DEVICE_FILE_NAME  "hello"    9 #define HELLO_DEVICE_PROC_NAME  "hello"   10 #define HELLO_DEVICE_CLASS_NAME "hello"   11  12 struct hello_android_dev { 13     int val; 14     struct semaphore sem; 15     struct cdev dev; 16 }; 17  18 #endif


hello.c #include <linux/init.h>  #include <linux/module.h>  #include <linux/types.h>  #include <linux/fs.h>  #include <linux/proc_fs.h>  #include <linux/device.h>  #include <asm/uaccess.h>    #include "hello.h"    /*主设备和从设备号变量*/  static int hello_major = 0;  static int hello_minor = 0;    /*设备类别和设备变量*/  static struct class* hello_class = NULL;  static struct hello_android_dev* hello_dev = NULL;    /*传统的设备文件操作方法*/  static int hello_open(struct inode* inode, struct file* filp);  static int hello_release(struct inode* inode, struct file* filp);  static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos);  static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos);    /*设备文件操作方法表*/  static struct file_operations hello_fops = {      .owner = THIS_MODULE,      .open = hello_open,      .release = hello_release,      .read = hello_read,      .write = hello_write,   };    /*访问设置属性方法*/  static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr,  char* buf);  static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count);    /*定义设备属性*/  static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store);  /*打开设备方法*/  static int hello_open(struct inode* inode, struct file* filp) {      struct hello_android_dev* dev;                    /*将自定义设备结构体保存在文件指针的私有数据域中,以便访问设备时拿来用*/      dev = container_of(inode->i_cdev, struct hello_android_dev, dev);      filp->private_data = dev;            return 0;  }    /*设备文件释放时调用,空实现*/  static int hello_release(struct inode* inode, struct file* filp) {      return 0;  }    /*读取设备的寄存器val的值*/  static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {      ssize_t err = 0;      struct hello_android_dev* dev = filp->private_data;                /*同步访问*/      if(down_interruptible(&(dev->sem))) {          return -ERESTARTSYS;      }        if(count < sizeof(dev->val)) {          goto out;      }                /*将寄存器val的值拷贝到用户提供的缓冲区*/      if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) {          err = -EFAULT;          goto out;      }        err = sizeof(dev->val);    out:      up(&(dev->sem));      return err;  }    /*写设备的寄存器值val*/  static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {      struct hello_android_dev* dev = filp->private_data;      ssize_t err = 0;                /*同步访问*/      if(down_interruptible(&(dev->sem))) {          return -ERESTARTSYS;              }                if(count != sizeof(dev->val)) {          goto out;              }                /*将用户提供的缓冲区的值写到设备寄存器去*/      if(copy_from_user(&(dev->val), buf, count)) {          err = -EFAULT;          goto out;      }        err = sizeof(dev->val);    out:      up(&(dev->sem));      return err;  }  /*读取寄存器val的值到缓冲区buf中,内部使用*/  static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) {      int val = 0;                /*同步访问*/      if(down_interruptible(&(dev->sem))) {                          return -ERESTARTSYS;              }                val = dev->val;              up(&(dev->sem));                return snprintf(buf, PAGE_SIZE, "%d\n", val);  }    /*把缓冲区buf的值写到设备寄存器val中去,内部使用*/  static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) {      int val = 0;                /*将字符串转换成数字*/              val = simple_strtol(buf, NULL, 10);                /*同步访问*/              if(down_interruptible(&(dev->sem))) {                          return -ERESTARTSYS;              }                dev->val = val;              up(&(dev->sem));        return count;  }    /*读取设备属性val*/  static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) {      struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);                return __hello_get_val(hdev, buf);  }    /*写设备属性val*/  static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) {       struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev);              return __hello_set_val(hdev, buf, count);  }  /*读取设备寄存器val的值,保存在page缓冲区中*/  static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) {      if(off > 0) {          *eof = 1;          return 0;      }        return __hello_get_val(hello_dev, page);  }    /*把缓冲区的值buff保存到设备寄存器val中去*/  static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) {      int err = 0;      char* page = NULL;        if(len > PAGE_SIZE) {          printk(KERN_ALERT"The buff is too large: %lu.\n", len);          return -EFAULT;      }        page = (char*)__get_free_page(GFP_KERNEL);      if(!page) {                          printk(KERN_ALERT"Failed to alloc page.\n");          return -ENOMEM;      }                /*先把用户提供的缓冲区值拷贝到内核缓冲区中去*/      if(copy_from_user(page, buff, len)) {          printk(KERN_ALERT"Failed to copy buff from user.\n");                          err = -EFAULT;          goto out;      }        err = __hello_set_val(hello_dev, page, len);    out:      free_page((unsigned long)page);      return err;  }    /*创建/proc/hello文件*/  static void hello_create_proc(void) {      struct proc_dir_entry* entry;            entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL);      if(entry) {        //  entry->owner = THIS_MODULE;          entry->read_proc = hello_proc_read;          entry->write_proc = hello_proc_write;      }  }    /*删除/proc/hello文件*/  static void hello_remove_proc(void) {      remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL);  }  /*初始化设备*/  static int  __hello_setup_dev(struct hello_android_dev* dev) {      int err;      dev_t devno = MKDEV(hello_major, hello_minor);        memset(dev, 0, sizeof(struct hello_android_dev));        cdev_init(&(dev->dev), &hello_fops);      dev->dev.owner = THIS_MODULE;      dev->dev.ops = &hello_fops;                /*注册字符设备*/      err = cdev_add(&(dev->dev),devno, 1);      if(err) {          return err;      }                /*初始化信号量和寄存器val的值*/      //init_MUTEX(&(dev->sem));      dev->val = 0;        return 0;  }    /*模块加载方法*/  static int __init hello_init(void){       int err = -1;      dev_t dev = 0;      struct device* temp = NULL;        printk(KERN_ALERT"Initializing hello device.\n");                /*动态分配主设备和从设备号*/      err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME);      if(err < 0) {          printk(KERN_ALERT"Failed to alloc char dev region.\n");          goto fail;      }        hello_major = MAJOR(dev);      hello_minor = MINOR(dev);                /*分配helo设备结构体变量*/      hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL);      if(!hello_dev) {          err = -ENOMEM;          printk(KERN_ALERT"Failed to alloc hello_dev.\n");          goto unregister;      }                /*初始化设备*/      err = __hello_setup_dev(hello_dev);      if(err) {          printk(KERN_ALERT"Failed to setup dev: %d.\n", err);          goto cleanup;      }                /*在/sys/class/目录下创建设备类别目录hello*/      hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME);      if(IS_ERR(hello_class)) {          err = PTR_ERR(hello_class);          printk(KERN_ALERT"Failed to create hello class.\n");          goto destroy_cdev;      }                /*在/dev/目录和/sys/class/hello目录下分别创建设备文件hello*/      temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME);      if(IS_ERR(temp)) {          err = PTR_ERR(temp);          printk(KERN_ALERT"Failed to create hello device.");          goto destroy_class;      }                /*在/sys/class/hello/hello目录下创建属性文件val*/      err = device_create_file(temp, &dev_attr_val);      if(err < 0) {          printk(KERN_ALERT"Failed to create attribute val.");                          goto destroy_device;      }        dev_set_drvdata(temp, hello_dev);                /*创建/proc/hello文件*/      hello_create_proc();        printk(KERN_ALERT"Succedded to initialize hello device.\n");      return 0;    destroy_device:      device_destroy(hello_class, dev);    destroy_class:      class_destroy(hello_class);    destroy_cdev:      cdev_del(&(hello_dev->dev));    cleanup:      kfree(hello_dev);    unregister:      unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1);    fail:      return err;  }    /*模块卸载方法*/  static void __exit hello_exit(void) {      dev_t devno = MKDEV(hello_major, hello_minor);        printk(KERN_ALERT"Destroy hello device.\n");                /*删除/proc/hello文件*/      hello_remove_proc();                /*销毁设备类别和设备*/      if(hello_class) {          device_destroy(hello_class, MKDEV(hello_major, hello_minor));          class_destroy(hello_class);      }                /*删除字符设备和释放设备内存*/      if(hello_dev) {          cdev_del(&(hello_dev->dev));          kfree(hello_dev);      }                /*释放设备号*/      unregister_chrdev_region(devno, 1);  }    MODULE_LICENSE("GPL");  MODULE_DESCRIPTION("First Android Driver");    module_init(hello_init);  module_exit(hello_exit);  

然后在 drivers/media/video/sunxi_csi/Kconfig 添加如下配置项:
zfl@Exdroid:~/android4.2-a20/android/lichee/linux-3.4$ git diff drivers/media/video/sunxi_csi/Kconfigdiff --git a/drivers/media/video/sunxi_csi/Kconfig b/drivers/media/video/sunxi_csi/Kconfigold mode 100644new mode 100755index 4489bbb..dcc2c8d--- a/drivers/media/video/sunxi_csi/Kconfig+++ b/drivers/media/video/sunxi_csi/Kconfig@@ -190,4 +190,12 @@ config CSI_GC2035        ---help---          This is a Video4Linux2 sensor-level driver for the GalaxyCore          GC2035 2M camera.-        \ No newline at end of file++config CSI_HELLO+           tristate "First Android Driver"+           default m+          select       CSI_DEV_SEL+           ---help---+           This is the first android driver


在drivers/media/video/sunxi_csi/device/Makefile 中添加如下编译项:
zfl@Exdroid:~/android4.2-a20/android/lichee/linux-3.4$ git diff drivers/media/video/sunxi_csi/device/Makefilediff --git a/drivers/media/video/sunxi_csi/device/Makefile b/drivers/media/video/sunxi_csi/device/Makefileold mode 100644new mode 100755index 69068e8..5868369--- a/drivers/media/video/sunxi_csi/device/Makefile+++ b/drivers/media/video/sunxi_csi/device/Makefile@@ -19,3 +19,4 @@ obj-$(CONFIG_CSI_S5K4EC)                            += s5k4ec.o obj-$(CONFIG_CSI_OV2643)                                       += ov2643.o obj-$(CONFIG_CSI_OV2655)                                       += ov2655.o obj-$(CONFIG_CSI_OV5640)                                       += ov5640.o+obj-$(CONFIG_CSI_HELLO) += hello.o


做好上述工作,下面对linux3.4进行编译,在编译的结果中drivers/media/video/sunxi_csi/device 目录下就会出现hello.ko文件。

我们只要将其放进已烧写好的固件中即可:
1.将其倒进到system/vendor/modules 中
2.在用insmod 命令将其进行加载,用busybox find ./ -name hello 看是否在相关目录有该设备。有即可对其进行相关的读写啦、

(注:由于环境不一样,在进行时,内核的驱动程序,以及在加载该驱动时相关的目录会有变化,比如我的下面就没有dev/hello 而直接是 /sys/devices/virtual/hello )


在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序

在上面,我们介绍了如何在Ubuntu上为Android系统编写Linux内核驱动程序。在这个名为hello的Linux内核驱动程序中,创建三个不同的文件节点来供用户空间访问,分别是传统的设备文件/dev/hello、proc系统文件/proc/hello和devfs系统属性文件/sys/class/hello/hello/val。进一步,还通过cat命令来直接访问/proc/hello和/sys/class/hello/hello/val文件来,以验证驱动程序的正确性。在这一篇文章里,我们将通过自己编写的C可执行程序来访问设备文件/dev/hello。可能读者会觉得奇怪,怎么能在Android系统中用C语言来编写应用程序呢?Android系统上的应用程序不都是Java应用程序吗?其实是可以的,读者不妨用adb shell命令连上Android模拟器,在/system/bin目录下可以看到很多C可执行程序,如cat命令。今天,我们就来学习一下怎么在Android系统中添加用C语言编写的可执行程序吧。

首先进入Android源代码工程的external目录,创建hello目录:
zfl@Exdroid:~/android4.2-a20/android/android4.2/external/hello$ croot
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ cd external/
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/external$  mkdir hello

在hello中创建hello.c文件
#include <stdio.h>                                                                                                                  #include <stdlib.h>  #include <fcntl.h>  //#define DEVICE_NAME "/dev/hello"  // no this dev#define DEVICE_NAME "/sys/devices/virtual/hello"int main(int argc, char** argv)  {      int fd = -1;      int val = 0;      fd = open(DEVICE_NAME, O_RDWR);      if(fd == -1) {           printf("Failed to open device %s.\n", DEVICE_NAME);          return -1;      }           printf("Read original value:\n");      read(fd, &val, sizeof(val));      printf("%d.\n\n", val);      val = 5;      printf("Write value %d to %s.\n\n", val, DEVICE_NAME);          write(fd, &val, sizeof(val));          printf("Read the value again:\n");          read(fd, &val, sizeof(val));          printf("%d.\n\n", val);      close(fd);      return 0;  }  


然后在hello中创建Android.mk文件:
LOCAL_PATH := $(call my-dir)                                                                                                              include $(CLEAR_VARS)      LOCAL_MODULE_TAGS := optional      LOCAL_MODULE := hello      LOCAL_SRC_FILES := $(call all-subdir-c-files)      include $(BUILD_EXECUTABLE)~                                                     

然后用mmm ./external/hello -j8 即可,最终将在out产品目录下面的system/bin下生成hello
将其push进系统,adb 进去system/bin 运行该hello即可。


在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序

接着上面讲,我们将通过设备文件/dev/hello来连接硬件抽象层模块和Linux内核驱动程序模块

进入到在hardware/libhardware/include/hardware目录,新建hello.h文件
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/hardware/libhardware/include/hardware$ 
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/hardware/libhardware/include/hardware$  vim hello.h

#ifndef ANDROID_HELLO_INTERFACE_H  #define ANDROID_HELLO_INTERFACE_H  #include <hardware/hardware.h>    __BEGIN_DECLS    /*定义模块ID*/  #define HELLO_HARDWARE_MODULE_ID "hello"    /*硬件模块结构体*/  struct hello_module_t {      struct hw_module_t common;  };    /*硬件接口结构体*/  struct hello_device_t {      struct hw_device_t common;      int fd;      int (*set_val)(struct hello_device_t* dev, int val);      int (*get_val)(struct hello_device_t* dev, int* val);  };    __END_DECLS    #endif  

这里按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。在硬件接口结构体中,fd表示设备文件描述符,对应我们将要处理的设备文件"/dev/hello",set_val和get_val为该HAL对上提供的函数接口。


进入到hardware/libhardware/modules目录,新建hello目录,并添加hello.c文件。

zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/hardware/libhardware/modules$ 
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/hardware/libhardware/modules/hello$ 
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/hardware/libhardware/modules/hello$  vim hello.c
#define LOG_TAG "HelloStub"    #include <hardware/hardware.h>  #include <hardware/hello.h>  #include <fcntl.h>  #include <errno.h>  #include <cutils/log.h>  #include <cutils/atomic.h>    #define DEVICE_NAME "/dev/hello"  #define MODULE_NAME "Hello"  #define MODULE_AUTHOR "shyluo@gmail.com"    /*设备打开和关闭接口*/  static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  static int hello_device_close(struct hw_device_t* device);    /*设备访问接口*/  static int hello_set_val(struct hello_device_t* dev, int val);  static int hello_get_val(struct hello_device_t* dev, int* val);    /*模块方法表*/  static struct hw_module_methods_t hello_module_methods = {      open: hello_device_open  };    /*模块实例变量*/  struct hello_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: &hello_module_methods,      }  };  static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {      struct hello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));            if(!dev) {          LOGE("Hello Stub: failed to alloc space");          return -EFAULT;      }        memset(dev, 0, sizeof(struct hello_device_t));      dev->common.tag = HARDWARE_DEVICE_TAG;      dev->common.version = 0;      dev->common.module = (hw_module_t*)module;      dev->common.close = hello_device_close;      dev->set_val = hello_set_val;dev->get_val = hello_get_val;        if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {          LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev);          return -EFAULT;      }        *device = &(dev->common);      LOGI("Hello Stub: open /dev/hello successfully.");        return 0;  }  static int hello_device_close(struct hw_device_t* device) {      struct hello_device_t* hello_device = (struct hello_device_t*)device;        if(hello_device) {          close(hello_device->fd);          free(hello_device);      }            return 0;  }    static int hello_set_val(struct hello_device_t* dev, int val) {      LOGI("Hello Stub: set value %d to device.", val);        write(dev->fd, &val, sizeof(val));        return 0;  }    static int hello_get_val(struct hello_device_t* dev, int* val) {      if(!val) {          LOGE("Hello Stub: error val pointer");          return -EFAULT;      }        read(dev->fd, val, sizeof(*val));        LOGI("Hello Stub: get value %d from device", *val);        return 0;  }  

继续在hello目录下新建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 := hello.c      LOCAL_MODULE := hello.default      include $(BUILD_SHARED_LIBRARY)

最后编译:
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ mmm ./hardware/libhardware/modules/hello -j8
编译成功后就可以在out的产品目录下的system/lib/hw看见hello.default.so了


在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口

 虽然在上面我们在Android系统为我们自己的硬件增加了一个硬件抽象层模块,但是现在Java应用程序还不能访问到我们的硬件。我们还必须编写JNI方法和在Android的Application Frameworks层增加API接口,才能让上层Application访问我们的硬件。

首先进入到frameworks/base/services/jni目录,新建com_android_server_HelloService.cpp文件
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/frameworks/base/services/jni$ zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/frameworks/base/services/jni$ vim com_android_server_HelloService.cpp

注意文件的命令方法,com_android_server前缀表示的是包名,表示硬件服务HelloService是放在frameworks/base/services/java目录下的com/android/server目录的,即存在一个命令为com.android.server.HelloService的类。这里,我们暂时略去HelloService类的描述,在下一篇文章中,我们将回到HelloService类来。简单地说,HelloService是一个提供Java接口的硬件访问服务类

#define LOG_TAG "HelloService"  #include "jni.h"  #include "JNIHelp.h"  #include "android_runtime/AndroidRuntime.h"  #include <utils/misc.h>  #include <utils/Log.h>  #include <hardware/hardware.h>  #include <hardware/hello.h>  #include <stdio.h>  namespace android  {      /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/          struct hello_device_t* hello_device = NULL;      /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/          static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {          int val = value;          LOGI("Hello JNI: set value %d to device.", val);          if(!hello_device) {              LOGI("Hello JNI: device is not open.");              return;          }                    hello_device->set_val(hello_device, val);      }          /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/      static jint hello_getVal(JNIEnv* env, jobject clazz) {          int val = 0;          if(!hello_device) {              LOGI("Hello JNI: device is not open.");              return val;          }          hello_device->get_val(hello_device, &val);                    LOGI("Hello JNI: get value %d from device.", val);                return val;      }          /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/      static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {          return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);      }          /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/      static jboolean hello_init(JNIEnv* env, jclass clazz) {          hello_module_t* module;                    LOGI("Hello JNI: initializing......");          if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {              LOGI("Hello JNI: hello Stub found.");              if(hello_device_open(&(module->common), &hello_device) == 0) {                  LOGI("Hello JNI: hello device is open.");                  return 0;              }              LOGE("Hello JNI: failed to open hello device.");              return -1;          }          LOGE("Hello JNI: failed to get hello stub module.");          return -1;            }          /*JNI方法表*/      static const JNINativeMethod method_table[] = {          {"init_native", "()Z", (void*)hello_init},          {"setVal_native", "(I)V", (void*)hello_setVal},          {"getVal_native", "()I", (void*)hello_getVal},      };          /*注册JNI方法*/      int register_android_server_HelloService(JNIEnv *env) {              return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));      }  };  

修改同目录下的onload.cpp文件,首先在namespace android增加register_android_server_HelloService函数声明

 namespace android {      ..............................................................................................      int register_android_server_HelloService(JNIEnv *env);      };


在JNI_onLoad增加register_android_server_HelloService函数调用:
 extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)      {       .................................................................................................       register_android_server_HelloService(env);       .................................................................................................      }

这样,在Android系统初始化时,就会自动加载该JNI方法调用表。

然后修改同目录下的Android.mk文件,在LOCAL_SRC_FILES变量中增加一行:
LOCAL_SRC_FILES:= \      com_android_server_AlarmManagerService.cpp \      com_android_server_BatteryService.cpp \      com_android_server_InputManager.cpp \      com_android_server_LightsService.cpp \      com_android_server_PowerManagerService.cpp \      com_android_server_SystemServer.cpp \      com_android_server_UsbService.cpp \      com_android_server_VibratorService.cpp \      com_android_server_location_GpsLocationProvider.cpp \      com_android_server_HelloService.cpp /      onload.cpp


最后编译:
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ mmm ./frameworks/base/services/jni/ -j8 
以及打包
pack xxxx

这样,重新打包的system.img镜像文件就包含我们刚才编写的JNI方法了,也就是我们可以通过Android系统的Application Frameworks层提供的硬件服务HelloService来调用这些JNI方法,进而调用低层的硬件抽象层接口去访问硬件了
下面将介绍如何在Android系统的Application Frameworks层提供Java接口的硬件服务。

在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务


上文中为硬件抽象层模块准备好JNI方法调用层。下面将介绍如何在Android系统的Application Frameworks层提供Java接口的硬件服务。

在Android系统中,硬件服务一般是运行在一个独立的进程中为各种应用程序提供服务。因此,调用这些硬件服务的应用程序与这些硬件服务之间的通信需要通过代理来进行。为此,我们要先定义好通信接口。进入到frameworks/base/core/java/android/os目录,新增IHelloService.aidl接口定义文件:
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ cd frameworks/base/core/java/android/os/
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/frameworks/base/core/java/android/os$ vim IHelloService.aidl

IHelloService.aidl定义了IHelloService接口: package android.os;     interface IHelloService {      void setVal(int val);      int getVal();  }  

返回到frameworks/base目录,打开Android.mk文件,修改LOCAL_SRC_FILES变量的值,增加IHelloService.aidl源文件:
 LOCAL_SRC_FILES += /   ....................................................................   core/java/android/os/IVibratorService.aidl /   core/java/android/os/IHelloService.aidl /   core/java/android/service/urlrenderer/IUrlRendererService.aidl /   .....................................................................

编译IHelloService.aidl接口

zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ mmm ./frameworks/base/

 这样,就会根据IHelloService.aidl生成相应的IHelloService.Stub接口。

进入到frameworks/base/services/java/com/android/server目录,新增HelloService.java文件:
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ cd frameworks/base/services/java/com/android/server/
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2/frameworks/base/services/java/com/android/server$ vim HelloService.java
package com.android.server;  import android.content.Context;  import android.os.IHelloService;  import android.util.Slog;  public class HelloService extends IHelloService.Stub {      private static final String TAG = "HelloService";      HelloService() {          init_native();      }      public void setVal(int val) {          setVal_native(val);      }         public int getVal() {          return getVal_native();      }            private static native boolean init_native();          private static native void setVal_native(int val);      private static native int getVal_native();  };  

HelloService主要是通过调用JNI方法init_native、setVal_native和getVal_native(见上面的JNI)来提供硬件服务


修改同目录的SystemServer.java文件,在ServerThread::run函数中增加加载HelloService的代码
@Override     public void run() {     ....................................................................................            try {                  Slog.i(TAG, "DiskStats Service");                  ServiceManager.addService("diskstats", new DiskStatsService(context));            } catch (Throwable e) {                  Slog.e(TAG, "Failure starting DiskStats Service", e);            }            try {                  Slog.i(TAG, "Hello Service");                  ServiceManager.addService("hello", new HelloService());            } catch (Throwable e) {                  Slog.e(TAG, "Failure starting Hello Service", e);            }

编译HelloService和重新打包system.img
zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ mmm ./frameworks/base/services/java/ -j8

zfl@Exdroid:/media/home2/zfl/android4.2-a20/android/android4.2$ pack xxx

这样,重新打包后的system.img系统镜像文件就在Application Frameworks层中包含了我们自定义的硬件服务HelloService了,并且会在系统启动的时候,自动加载HelloService。这时,应用程序就可以通过Java接口来访问Hello硬件服务了。



在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务

这里我们将在Android系统的应用层增加一个内置的应用程序,这个内置的应用程序通过ServiceManager接口获取指定的服务,然后通过这个服务来获得硬件服务。

package com.flzhang.hello;    import com.flzhang.hello.R;  import android.app.Activity;  import android.os.ServiceManager;  import android.os.Bundle;  import android.os.IHelloService;  import android.os.RemoteException;  import android.util.Log;  import android.view.View;  import android.view.View.OnClickListener;  import android.widget.Button;  import android.widget.EditText;    public class Hello extends Activity implements OnClickListener {      private final static String LOG_TAG = "com.flzhang.Hello";            private IHelloService helloService = null;        private EditText valueText = null;      private Button readButton = null;      private Button writeButton = null;      private Button clearButton = null;            /** Called when the activity is first created. */      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);        helloService = IHelloService.Stub.asInterface(          ServiceManager.getService("hello"));                    valueText = (EditText)findViewById(R.id.edit_value);          readButton = (Button)findViewById(R.id.button_read);          writeButton = (Button)findViewById(R.id.button_write);          clearButton = (Button)findViewById(R.id.button_clear);        readButton.setOnClickListener(this);      writeButton.setOnClickListener(this);      clearButton.setOnClickListener(this);                    Log.i(LOG_TAG, "Hello Activity Created");      }            @Override      public void onClick(View v) {          if(v.equals(readButton)) {          try {                  int val = helloService.getVal();                  String text = String.valueOf(val);                  valueText.setText(text);          } catch (RemoteException e) {              Log.e(LOG_TAG, "Remote Exception while reading value from device.");          }                 }          else if(v.equals(writeButton)) {          try {                  String text = valueText.getText().toString();                  int val = Integer.parseInt(text);              helloService.setVal(val);          } catch (RemoteException e) {              Log.e(LOG_TAG, "Remote Exception while writing value to device.");          }          }          else if(v.equals(clearButton)) {              String text = "";              valueText.setText(text);          }      }  }  

程序通过ServiceManager.getService("hello")来获得HelloService,接着通过IHelloService.Stub.asInterface函数转换为IHelloService接口。其中,服务名字“hello”是系统启动时加载HelloService时指定的,而IHelloService接口定义在android.os.IHelloService中

编译,push进系统即可。
-------------感谢老罗.............^--^.......................