Android系统开发入门

Android系统开发入门
Android系统开发入门

Android系统开发入门

注:相信大家都知道Android的APP的是用Java写的,运行在Dalvik 虚拟机上,还有,Android的系统是基于Linux Kernel 2.6的。那么,要想深入了解Android系统的各种细节,当然少不了Linux Kernel 的知识了。阅读本文需要具备一定的C和JAVA语言基础,并且对linux 系统有一定了解。最好对C++也有一定的了解。

本文的内容是基于Android2.2版本平台,以一个设备(将系统内存模拟成一个带4字节寄存器的设备)为例,从底层驱动,到中间件,到上层应用程序全过程的代码实现。

所编写的代码例子,都可以在Android模拟器进行运行。但由于https://www.360docs.net/doc/3a15985658.html,在2011年9月份被人黑了无法访问,导致本人没有下载goldfish_defconfig,无法编译能在模拟器运行的kernel,故采用JZ4760BLYNX开发板运行代码例子。

搭建好JZ android编译环境,开始进行android系统开发之旅。

Android硬件抽象层(HAL)概要介绍和学习计划

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

撇开这些争论,学习Android硬件抽象层,对理解整个Android整个系统,都是极其有用的,因为它从下到上涉及到了Android系统的硬件驱动层、硬件抽象层、运行时库和应用程序框架层等等,下面这个图阐述了硬件抽象层在Android系统中的位置,以及它和其它层的关系:

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

一、在Android内核源代码工程(kernel)中编写硬件驱动程序 (3)

二、在Android系统中增加C可执行程序来访问硬件驱动程序。 (14)

三、在Android硬件抽象层(HAL)增加接口模块访问硬件驱动程序 (17)

四、在Android系统中编写JNI方法在应用程序框架层提供Java接口访问硬

件22

五、在Android系统的应用程序框架层(Framework)增加硬件服务接口 (26)

六、在Android系统中编写APP通过应用程序框架层访问硬件服务 (28)

一、在Android内核源代码工程(kernel)中编写硬件驱动程序

在智能手机和平板时代,每个品牌的产品都有自己的个性特点。正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非iphone莫属了。据统计,截止2011年5月,AppStore的应用软件数量达381062个,位居第一,而Android Market

的应用软件数量达294738,紧随AppStore后面,并有望在8月份越过AppStore。随着Android 系统逐步扩大市场占有率,终端设备的多样性亟需更多的移动开发人员的参与。据业内统计,Android研发人才缺口至少30万。目前,对Android人才需求一类是偏向硬件驱动的Android 人才需求,一类是偏向软件应用的Android人才需求。总的来说,对有志于从事Android硬件驱动的开发工程师来说,现在是一个大展拳脚的机会。那么,就让我们一起来看看如何为Android系统编写内核驱动程序吧。

这里,我不会为真实的硬件设备编写内核驱动程序。为了方便描述为Android系统编写内核驱动程序的过程,我使用一个虚拟的硬件设备,这个设备只有一个4字节的寄存器,它可读可写。想起我们第一次学习程序语言时,都喜欢用“Hello, World”作为例子,这里,我就把这个虚拟的设备命名为“hello”,而这个内核驱动程序也命名为hello驱动程序。其实,Android内核驱动程序和一般Linux内核驱动程序的编写方法是一样的,都是以Linux模块的形式实现的,具体可参考《Linux Device Drivers》一书。不过,这里我还是从Android系统的角度来描述Android内核驱动程序的编写和编译过程。

一.,进入到kernel/drivers目录,新建hello目录:

zyhu@ubuntu-50:~/work/kernel$ cd drivers/

zyhu@ubuntu-50:~/work/kernel/drivers$ mkdir hello

一,在hello目录中增加hello.h文件:

hello.h

#ifndef _HELLO_ANDROID_H_

#define _HELLO_ANDROID_H_

#include

#include

#define HELLO_DEVICE_NODE_NAME "hello"

#define HELLO_DEVICE_FILE_NAME "hello"

#define HELLO_DEVICE_PROC_NAME "hello"

#define HELLO_DEVICE_CLASS_NAME "hello"

struct hello_android_dev {

int val;

struct semaphore sem;

struct cdev dev;

};

#endif

这个头文件定义了一些字符串常量宏,在后面我们要用到。此外,还定义了一个字符设备结构体hello_android_dev,这个就是我们虚拟的硬件设备了,val成员变量就代表设备里面的寄存器,它的类型为int,sem成员变量是一个信号量,是用同步访问寄存器val的,dev成员变量是一个内嵌的字符设备,这个Linux驱动程序自定义字符设备结构体的标准方法。

三,在hello目录中增加hello.c文件,这是驱动程序的实现部分。驱动程序的功能主要是向

上层提供访问设备的寄存器的值,包括读和写。这里,提供了三种访问设备寄存器的方法,一是通过proc文件系统来访问,二是通过传统的设备文件的方法来访问,三是通过devfs 文件系统来访问。下面是该驱动程序的实现。我会对代码分段注释描述。

Hello.c

/*包含必要的头文件和定义三种访问设备的方法:*/

#include

#include

#include

#include

#include

#include

#include

#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);

/* 定义传统的设备文件访问方法,主要是定义hello_open、hello_release、hello_read和hello_write这四个打开、释放、读和写设备文件的方法:*/

/*打开设备方法*/

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;

}

/* 定义通过devfs文件系统访问方法,这里把设备的寄存器val看成是设备的一个属性,通过读写这个属性来对设备进行访问,主要是实现hello_val_show和hello_val_store两个方法,同时定义了两个内部使用的访问val值的方法__hello_get_val和__hello_set_val:*/

/*读取寄存器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);

}

/* 定义通过proc文件系统访问方法,主要实现了hello_proc_read和hello_proc_write两个方法,同时定义了在proc文件系统创建和删除文件的方法hello_create_proc和hello_remove_proc:*/

/*读取设备寄存器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* d ata) {

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->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.\n");

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.\n");

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_AUTHOR("Huzhangyzn");

MODULE_DESCRIPTION("First Android Driver Hello");

MODULE_VERSION("V1.0");

MODULE_ALIAS("A Simple Android Driver");

module_init(hello_init);

module_exit(hello_exit);

四,在hello目录中新增Kconfig和Makefile两个文件,其中Kconfig是在编译前执行配置命令make menuconfig时用到的,而Makefile是执行编译命令make是用到的:

Kconfig文件的内容

config HELLO

tristate "First Android Driver"

default n

help

This is the first android driver.

Makefile文件的内容

obj-$(CONFIG_HELLO) += hello.o

在Kconfig文件中,tristate表示编译选项HELLO支持在编译内核时,hello模块支持以模块、内建和不编译三种编译方法,默认是不编译,因此,在编译内核前,我们还需要执行make menuconfig命令来配置编译选项,使得hello可以以模块或者内建的方法进行编译。

在Makefile文件中,根据选项HELLO的值,执行不同的编译方法。

五,修改drivers/kconfig文件,在menu "Device Drivers"和endmenu之间添加一行:source "drivers/hello/Kconfig"

这样,执行make menuconfig时,就可以配置hello模块的编译选项了。.

六.,修改drivers/Makefile文件,添加一行:

obj-$(CONFIG_HELLO) += hello/

七,配置编译选项:

zyhu@ubuntu-50:~/work/kernel$ make menuconfig

找到"Device Drivers" => "First Android Drivers"选项,设置为*。

注意,如果内核不支持动态加载模块,这里不能选择m,虽然我们在Kconfig文件中配置了HELLO选项为tristate。要支持动态加载模块选项,必须要在配置菜单中选择Enable loadable module support选项;在支持动态卸载模块选项,必须要在Enable loadable module support菜单项中,选择Module unloading选项。

八,编译:

zyhu@ubuntu-50:~/work$ ./summon mkbootimg.sh lynx

编译成功后,就可以在hello目录下看到hello.o文件了,这时候编译出来的boot.img已经包含了hello驱动。

九,验证:

将新kernel(boot.img)烧入进开发板,启动机器,连接USB线。adb shell :

进入到dev目录,可以看到hello设备文件:

root@android:/ # cd dev

root@android:/dev # ls

进入到proc目录,可以看到hello文件:

root@android:/ # cd proc

root@android:/proc # ls

访问hello文件的值:

root@android:/proc # cat hello

root@android:/proc # echo '5' > hello

root@android:/proc # cat hello

5

进入到sys/class目录,可以看到hello目录:

root@android:/ # cd sys/class

root@android:/sys/class # ls

进入到hello目录,可以看到hello目录:

root@android:/sys/class # cd hello

root@android:/sys/class/hello # ls

进入到下一层hello目录,可以看到val文件:

root@android:/sys/class/hello # cd hello

root@android:/sys/class/hello/hello # ls

访问属性文件val的值:

root@android:/sys/class/hello/hello # cat val

5

root@android:/sys/class/hello/hello # echo '0' > val

root@android:/sys/class/hello/hello # cat val

至此,我们的hello内核驱动程序就完成了,并且验证一切正常。

小结:这里我们采用的是系统提供的方法和驱动程序进行交互,也就是通过proc文件系统和devfs文件系统的方法,实际开发中可根据需要选择。

下一节文章中,我们将通过自己编译的C语言程序来访问/dev/hello文件来和hello 驱动程序交互,敬请期待。

二、在Android系统中增加C可执行程序来访问硬件驱动

程序

在上一章节中,我介绍了如何为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目录:

zyhu@ubuntu-50:~/work$ cd external/

zyhu@ubuntu-50:~/work/external$ mkdir hello

二,在hello目录中新建hello.c文件:

hello.c

#include

#include

#include

#include

#define DEVICE_NAME "/dev/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;

}

这个程序的作用中,打开/dev/hello文件,然后先读出/dev/hello文件中的值,接着写入值5到/dev/hello中去,最后再次读出/dev/hello文件中的值,看看是否是我们刚才写入的值5。从/dev/hello文件读写的值实际上就是我们虚拟的硬件的寄存器val的值。

二,在hello目录中新建Android.mk文件:

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_V ARS)

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE := hello

LOCAL_SRC_FILES := $(call all-subdir-c-files)

include $(BUILD_EXECUTABLE)

注意,BUILD_EXECUTABLE表示我们要编译的是可执行程序。

三,使用mmm或者mm进行编译

zyhu@ubuntu-50:~/work/external/hello$ mm

编译成功后,就可以在out/target/product/lynx/system/bin目录下,看到可执行文件hello了。

五,重新打包Android系统文件system.img:

zyhu@ubuntu-50:~/work$ ./summon mkext4img.sh lynx system

这样,重新打包后的system.img文件就包含刚才编译好的hello可执行文件了。

六,验证:

将新system(system.img)烧入进开发板,启动机器, 使用/system/bin/hello可执行程序来访问Linux内核驱动程序。

root@android:/ # cd system/bin

root@android:/system/bin # ./hello

Read the original value:

0.

Write value 5 to /dev/hello.

Read the value again:

5.

看到这个结果,就说我们编写的C可执行程序可以访问我们编写的Linux内核驱动程序了。

小结:这里我们介绍的是如何使用C语言编写的可执行程序来访问我们的Linux内核驱动程序,学过Linux开发的读者肯定十分熟悉,这就是linux开发的典型模式。读者可能会问,我们现在讲的是Android开发,而Android的应用程序是Java语言编写的,能不能在Android

的Application Frameworks提供Java接口来访问Linux内核驱动程序呢?可以的,接下来的几个章节中,我们将介绍如何在Android的Application Frameworks中,增加Java接口来访问Linux内核驱动程序,敬请期待。

三、在Android硬件抽象层(HAL)增加接口模块访问硬件

驱动程序

在Android硬件抽象层(HAL)概要介绍和学习计划一文中,我们简要介绍了在Android系统为硬件编写驱动程序的方法。简单来说,硬件驱动程序一方面分布在Linux内核中,另一方面分布在用户空间的硬件抽象层中。在章节一Android内核源代码工程中编写硬件驱动程序一文中举例子说明了如何在Linux内核编写驱动程序。在这一章节中,我们将继续介绍Android系统硬件驱动程序的另一方面实现,即如何在硬件抽象层中增加硬件模块来和内核驱动程序交互。在这篇文章中,我们还将学习到如何在Android系统创建设备文件时用类似Linux的udev规则修改设备文件模式的方法。

一,参照Android内核源代码工程中编写硬件驱动程序一文所示,准备好示例内核驱动序。完成这个内核驱动程序后,便可以在Android系统中得到三个文件,分别是/dev/hello、/sys/class/hello/hello/val和/proc/hello。在本文中,我们将通过设备文件/dev/hello来连接硬件抽象层模块和Linux内核驱动程序模块。

二,进入到在hardware/libhardware/include/hardware目录,新建hello.h文件:zyhu@ubuntu-50:~/work$ cd hardware/libhardware/include/hardware/

zyhu@ubuntu-50:~/work/hardware/libhardware/include/hardware$ vim hello.h

hello.h

#ifndef ANDROID_HELLO_INTERFACE_H

#define ANDROID_HELLO_INTERFACE_H

#include

__BEGIN_DECLS

/*定义模块ID*/

#define HELLO_HARDW ARE_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文件。

zyhu@ubuntu-50:~/work/hardware/libhardware/modules$ mkdir hello

zyhu@ubuntu-50:~/work/hardware/libhardware/modules/hello$ vim hello.c

同样,我对hello.c分段注释。

hello.c

/* 首先是包含相关头文件和定义相关结构:*/

#define LOG_TAG "HelloStub"

#include

#include

#include

#include

#include

#include

#define DEVICE_NAME "/dev/hello"

#define MODULE_NAME "Hello"

#define MODULE_AUTHOR "shyluo@https://www.360docs.net/doc/3a15985658.html,"

/*设备打开和关闭接口*/

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_devi ce_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: HARDW ARE_MODULE_TAG,

version_major: 1,

version_minor: 0,

id: HELLO_HARDW ARE_MODULE_ID,

name: MODULE_NAME,

author: MODULE_AUTHOR,

methods: &hello_module_methods,

}

};

/*这里,实例变量名必须为HAL_MODULE_INFO_SYM,tag也必须为HARDW ARE_MODULE_TAG,这是Android硬件抽象层规范规定的。*/

/*定义hello_device_open函数:*/

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_devi ce_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 = HARDW ARE_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;

}

/*定义hello_device_close、hello_set_val和hello_get_val这三个函数:*/

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文件:

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_V ARS)

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)

注意,LOCAL_MODULE的定义规则,hello后面跟有default,hello.default能够保证我们的模块总能被硬象抽象层加载到

五,编译:

zyhu@ubuntu-50:~/work/hardware/libhardware/modules/hello$ mm

编译成功后,就可以在out/target/product/lynx/system/lib/hw/目录下看到hello.default.so文件了。

六. 重新打包Android系统镜像system.img:

Android驱动开发实例(控制LED灯)(精)

Android驱动例子(LED灯控制) 本例子,讲述在Android2.1上完全自已开发一个驱动去控制硬件口并写应用测试该驱动,通过这样一个例子,解析android下的驱动开发流程的应用调用流程,可以说是很好的入门引导 要达到的效果:通过Android的应用,调用驱动程序,在开发板上控制4个LED的亮灭。 一、硬件原理 如上图,通过4个IO口控制这LED,低电平LED亮, 这4个IO口分别是GPM1, GPM2, GPM3, GPM4, 二、驱动程序 1、在kernel文件夹下的driver目录,新键驱动文件夹 # cd kernel_Android_2.6.28.6/drivers 进到开发板的kernel目录,建驱动文件夹 #mkdir ledtest

2、在/driver/ledtest目录下,新建leddriver.c ,leddriver.h , Kconfig, Makefile 等4个文件leddriver.c leddriver.c 1. #include 2. #include 3. #include 4. #include/* For __init/__exit/... */ 5. #include 6. #include 7. #include 8. #include 9. #include 10. #include 11. #include 12. #include 13. #include 14. #include 15. #include 16. #include 17. #include//for register_chrdev( 18. #include 19. #include 20. #include"leddriver.h" 21. #include/* For MODULE_ALIAS_MISCDEV 22. (WATCHDOG_MINOR */ 23. #include/* For the watchdog specific items */ 24. #include/* For file operations */ 25. #define Viberator_MAJOR 97 //?÷éè±?o? 26. #define SCULL_NR_DEVS 4 27. #define SCULL_QUANTUM 4000 28. #define SCULL_QSET 1000 29. //---do as the GIO driver

android系统开发--HAL层开发基础

android系统开发--HAL层开发基础 Android HAL层,即硬件抽象层,是Google响应厂家“希望不公开源码”的要求推出的新概念 1,源代码和目标位置 源代码:/hardware/libhardware目录,该目录的目录结构如下: /hardware/libhardware/hardware.c编译成libhardware.so,目标位置为/system/lib目录 /hardware/libhardware/include/hardware目录下包含如下头文件: hardware.h 通用硬件模块头文件 copybit.h copybit模块头文件 gralloc.h gralloc模块头文件 lights.h 背光模块头文件 overlay.h overlay模块头文件 qemud.h qemud模块头文件 sensors.h 传感器模块头文件 /hardware/libhardware/modules目录下定义了很多硬件模块 这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录 2,HAL层的实现方式 JNI->通用硬件模块->硬件模块->内核驱动接口 具体一点:JNI->libhardware.so->xxx.xxx.so->kernel 具体来说:android frameworks中JNI调用/hardware/libhardware/hardware.c中定义的hw_get_module函数来获取硬件模块, 然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能 3,通用硬件模块(libhardware.so) (1)头文件为:/hardware/libhardware/include/hardware/hardware.h 头文件中主要定义了通用硬件模块结构体hw_module_t,声明了JNI调用的接口函数 hw_get_module hw_module_t定义如下: typedef struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; /** major version number for the module */ uint16_t version_major; /** minor version number of the module */ uint16_t version_minor; /** Identifier of module */ const char *id; /** Name of this module */ const char *name;

嵌入式linux android驱动工程师 面试题总汇

嵌入式linux android驱动工程师面试题总汇 1. 嵌入式系统中断服务子程序(ISR) 收藏中断是嵌入式系统中重要的组成 部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt 关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。 __interrupt double compute_area (double radius) { double area = PI * radius * radius; printf(" Area = %f", area); return area; } 1). ISR 不能返回一个值。2). ISR 不能传递参数。3). 在许多的处理器/编译器中,浮点一般都是不可重入的。有些处理器/编译器需要让额处的寄存器入栈,有些处理器/编译器就是不允许在ISR中做浮点运算。此外,ISR应该是短而有效率的,在ISR中做浮点运算是不明智的。4). 与第三点一脉相承,printf()经常有重入和性能上的问题。 2.C语言中对位的操作,比如对a的第三位清0,第四位置1.本来应该会的,一犯晕写反了,以后注意! #define BIT3 (1<<3) #define BIT4 (1<<4) a &= ~BIT3; a |= BIT4; 3.考到volatile含义并举例:理解出错,举了很具体的例子,连程序都搬上去了,有些理解不深的没举出来…… volatile表示这个变量会被意想不到的改变,每次用他的时候都会小心的重新读取一遍,不适用寄存器保存的副本。 volatile表示直接存取原始地址 例: 并行设备的硬件寄存器(状态寄存器) 在多线程运行的时候共享变量也要时时更新 一个中断服务子程序中访问到的的非自动变量(不太清楚,正在查找资料ing……) 4.要求设置一绝对地址为0x67a9 的整型变量的值为0xaa66 当时我的写法:#define AA *(volatile unsigned long *)0xaa66 AA = 0x67a9; 答案:

Android移动应用开发习题答案

Android移动应用开发习题答案 单元1 Android开发环境搭建与模拟器创建 1.填空题 (1) 2008 (2) Linux、操作系统 (3) 应用程序层、应用程序框架层、核心类库、Linux内核 (4) Java C++/C (5) 应用框架 (6) 应用程序 (7) 模拟器、Android模拟器 (8) IntelliJ IDEA Android 2.选择题 (1)创建程序的过程中,填写Application Name表示()。 正确答案:A (2)Android操作系统的手机可以有以下几个方法进行软件安装()。(多选题)ABCD (3)Android操作系统主要的特点是:()。(多选题) 正确答案:ABC (4)以下对Android操作系统描述正确的是:()。(多选题) 正确答案:ABCD (5)以下哪些是Android Stuido的优势()。(多选题) 正确答案:ABCD (6)以下哪些是Genymotion模拟器的优势()。(多选题) 正确答案:ABCD 3.简答题 (1)Android的四层架构分别包括哪几层?分别起到什么作用? 参考答案: Linux内核层(Linux Kernel):基于Linux内核,内核为上层系统提供了系统服务。 核心类库层(Libraries):系统库基于C/C++语言实现,通过接口向应用程序框架层提

基于Android Studio的移动应用开发任务驱动教程 供编程接口。 应用框架层(Application Framework):为开发者提供了一系列的Java API,包括图形用户界面组件View、SQLite数据库相关的API、Service组件等。 应用程序层(Applications):包含了Android平台中各式各样的应用程序。 (2)简述Android开发环境安装的步骤。 参考答案: 下载并安装JDK,配置JDK的环境变量; 从Anroid官网上下载Android开发组件(包含Eclipse和Android SDK、ADT); 安装Android开发环境(包括配置Android SDK的环境变量、打开Eclipse通过菜单设定Android SDK路径)。 (3)简述Android Studio的优势。 参考答案:略。 (4)简述Genymotion模拟器的优势。 参考答案:略。 (5)简述Android应用程序创建和运行的步骤。 参考答案: 通过菜单创建Android应用程序,设置应用程序名、Android版本等基本信息。 单击菜单中的运行按钮可以直接运行Android项目(也可以通过菜单配置运行参数, 指定运行的模拟器)。 单元2 Android Studio的组成结构与基本操作 1.填空题 (1) res/layout (2) Activity、Bundle (3) XML (4) java代码文件 (5) AndroidManifest.xml (6) 打包成.apk文件 2.选择题 (1)如果需要创建一个字符串资源,需要将字符串放在res\values的哪个文件中?()B (2)新建的Android程序默认的布局方式是相对布局(RelativeLayout),该布局中包含一个()控件。 B (3)要让布局文件或者控件能够显示在界面上,必须要设置RelativeLayout和控件的

51CTO学院-Android驱动与HAL开发实战视频课程

Android驱动与HAL开发实战视频课程 课程目标 本教程主要讲解了如何开发Android底层的驱动程序(Linux驱动),以及Android HAL的开发。并使用蜂鸣器等demo来讲解。 适用人群 了解Android的基本知识,想从事Android底层开发的学员。 课程简介 课程目标: 本教程主要讲解了如何开发Android底层的驱动程序(Linux驱动),以及Android HAL的开发。并使用蜂鸣器等demo来讲解。 适合对象: 了解Android的基本知识,想从事Android底层开发的学员。 学习条件: 熟悉Linux的基本操作和C语言 1 Android底层开发概述 [免费观看] 47分钟 本讲主要介绍了Android底层开发概况、Android底层架构、Linux驱动程序的基本结构等内容。 2 搭建开发环境 [免费观看] 44分钟 本讲主要介绍了如何搭建用于开发Android底层的开发环境。 3 源代码下载和编译 45分钟 本讲主要介绍了如何编译Android源代码和Linux内核源代码。并且如何下载这些系统的源代码。 4

搭建S3C6410开发板的测试环境 40分钟 本讲主要介绍了如何搭建S3C6410开发板(Android系统)的开发测试环境。本教程后面的蜂鸣器、LED驱动开发都会使用这个开发板进行开发和测试,其他类似的开发板也同样适用。不过需要向厂家或销售商索要相应的驱动。其余的例子也可以在手机和平板电脑上测试。 5 第一个Linux驱动_读写设备文件(1) [免费观看] 45分钟 本讲主要介绍了如何开发第一个有读写功能的Linux驱动程序(第一部分) 6 第一个Linux驱动_读写设备文件(2) [免费观看] 47分钟 本讲主要介绍了实现第一个Linux驱动的第二部分。 7 实现LED驱动(1) 42分钟 本讲主要介绍了实现LED驱动的基本方法,并实现了这个LED驱动(第一部分)。 8 实现LED驱动(2) 42分钟 本讲主要介绍了实现LED驱动的基本方法,并实现了这个LED驱动(第二部分)。 9 实现LED驱动(3) 47分钟 本讲主要介绍了实现LED驱动的基本方法,并实现了这个LED驱动(第三部分)。 10

Android驱动---LED驱动的编写汇总

Android驱动---LED驱动的编写 1.编写Android驱动时,首先先要完成Linux驱动,因为android驱动其实是在linux驱动基础之上完成了HAL层(硬件抽象层),如果想要测试的话,自己也要编写Java程序来测试你的驱动。 2.android的根文件系统是eclair_2.1版本。我会上传做好的根文件系统提供大家。这里要说的是,android底层内核还是linux的内核,只是进行了一些裁剪。做好的linux内核镜像,这个我也会上传给大家。android自己做了一套根文件系统,这才是android自己做的东西。android事实上只是做了一套根文件系统罢了。 假设linux驱动大家都已经做好了。我板子上有四个灯,通过ioctl控制四个灯,给定不同的参数,点亮不同的灯。 linux驱动代码因平台不同而有所不同,这就不黏代码了。 这是我测试linux驱动编写的驱动,代码如下: [cpp] view plaincopy #include #include #include #include #include #include #include #include #define LED_ON _IO ('k',1) #define LED_OFF _IO ('k',2) int main() { int i = 0; int dev_fd; dev_fd = open("/dev/led",O_RDWR); if ( dev_fd == -1 ) { printf("Cann't open file /dev/led\n"); exit(1); } while(1) { ioctl(dev_fd,LED_ON,1); sleep(1); ioctl(dev_fd,LED_OFF,1); sleep(1); ioctl(dev_fd,LED_ON,2); sleep(1); ioctl(dev_fd,LED_OFF,2);

Android Linux驱动开发工程师简历模板

Megan简历 工作经历 XX有限公司2016年09月- 2019年10月Android/Linux驱动开发工程师 带领驱动开发团队进行DM8127平台的定制开发,完成inux内核/uboot移植,外围驱动移植与开发, 基于IPNCRDK 搭建视频采集,降噪,编码、输出的数据流。配合应用团队实现智能交通抓拍业务。负责技术方案的预研和选型。负责软件版本需求评估、实现评估,工作分配,版本构建和发布、测试故障指派和处理等。 负责Atmel maxtouch电容触摸产品线技术开发与支持,包括Android驱动开发支持和项目性能调试和优化等。负责MIPI 桥接芯片和DDI显示驱动芯片技术支持。负责团队的建设和协调,以及开发进度的跟踪。 XX有限公司 2014年07月- 2016年08月Android/Linux驱动开发工程师 负责几款公司开发的ARM+DSP多媒体处理器芯片的测试、应用开发;这几款芯片广泛应用于Android平板电脑、微型投影机、电子书、MID等领域。 熟悉codec图像编解码算法,dsp底层算法库,主要用汇编开发,独立解决了编解码双核调度的问题。熟练使用c/c++。阅读过Android操作系统ion源码 公司ti平台开发板WinCE系统BSP,公司ti和freescale平台开发板的Android系统BSP开发和驱动开发,负责开发了一个RTSP流媒体的流媒体,把上级领导交代的工作尽快做好,提高工作效率。 教育经历 成都信息工程学院2010年09月- 2014年06月电子科学与技术本科 成都其他 技能:Dsp,Word,C/C++,Wince,Excel,Android,操作系统,办公软件 语言:普通话二级甲等证书

Android之蓝牙驱动开发总结

Android之蓝牙驱动开 发总结

二Android Bluetooth架构 (1) 2.1 Bluetooth架构图 (1) 2.2 Bluetooth代码层次结构 (3) 三Bluetooth协议栈分析 (4) 3.1 蓝牙协议栈 (4) 3.2 Android与蓝牙协议栈的关系 (5) 四Bluetooth之HCI层分析 (5) 4.1 HCI层与基带的通信方式 (6) 4.2 包的分析及研究 (7) 4.3 通信过程的研究与分析 (8) 五Bluetooth之编程实现 (8) 5.1 HCI层编程 (8) 5.2 L2CAP层编程 (10) 5.3 SDP层编程 (12) 六Bluetooth之启动过程实现 (13) 6.1 Bluetooth启动步骤 (14) 6.2 Bluetooth启动流程 (14) 6.3 Bluetooth数据流向 (14) 6.4 Bluez控制流程 (14) 6.5 Bluetooth启动过程分析 (15) 七Bluetooth之驱动移植 (15) 7.1 android系统配置 (15) 7.2 启动项修改 (16) 7.3 电源管理rfkill驱动 (16) 7.4 Rebuild Android image and reboot (16) 7.5 实现BT睡眠唤醒机制 (16) 7.6 系统集成 (17) 八Bluetooth之调试与编译 (17) 8.1 Bluetooth驱动调试 (17)

九Bluetooth之应用程序开发 (18) 9.1 Bluetooth的API开发 (18) 9.2 The Basics开发 (18) 9.3 Bluetooth Permissions开发 (19) 9.4 Setting Up Bluetooth服务 (19) 9.5 Finding Devices服务 (20) 9.6 Connecting Devices服务 (22) 9.7 Managing a Connection服务 (26) 9.8 Working with Profiles服务 (28) 十总结与疑问 (29)

Android底层驱动开发

Android 开发之---- 底层驱动开发(一) 说到android 驱动是离不开Linux驱动的。Android内核采用的是Linux2.6内核(最近Linux 3.3已经包含了一些Android代码)。但Android并没有完全照搬Linux系统内核,除了对Linux进行部分修正,还增加了不少内容。android 驱动主要分两种类型:Android专用驱动和Android使用的设备驱动(linux)。Android 专有驱动程序: 1)Android Ashmem 匿名共享内存;为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。 2)Android Logger 轻量级的LOG(日志)驱动; 3)Android Binder 基于OpenBinder框架的一个驱动; 4)Android Power Management 电源管理模块; 5)Low Memory Killer 低内存管理器; 6)Android PMEM 物理内存驱动; 7)USB Gadget USB 驱动(基于gaeget 框架); 8)Ram Console 用于调试写入日志信息的设备; 9)Time Device 定时控制设备; 10)Android Alarm 硬件时钟; Android 上的设备驱动(linux): 1)Framebuff 显示驱动; 2)Event 输入设备驱动; 3)ALSA 音频驱动; 4)OSS 音频驱动; 5)v412摄像头:视频驱动; 6)MTD 驱动; 7)蓝牙驱动; 8)WLAN 设备驱动; Android 专有驱动程序 1.Android Ashmem 为用户空间程序提供分配内存的机制,为进程间提供大块共享内存,同时为内核提供回收和管理这个内存。 设备节点:/dev/ashmen .主设备号10. 源码位置:include/linux/ashmen.h Kernel /mm/ashmen.c 相比于malloc和anonymous/named mmap等传统的内存分配机制,其优势是通过内核驱动提供了辅助内核的内存回收算法机制(pin/unoin)

Android驱动开发示例及系统编译

Android驱动开发示例及系统编译 1基础部分 在Ubuntu上下载、编译和安装Android最新源代码 看完了前面说的几本书之后,对Linux Kernel和Android有一定的认识了,是不是心里蠢蠢欲动,想小试牛刀自己编译一把Android源代码了呢?一直习惯使用Windows系统,而Android源代码是不支持在Windows上编译上,于是决定使用虚拟机安装Ubuntu,然后下载、编译和安装Android源代码。 一. 环境准备 1. 磁盘空间预留20G左右,存3G,因为一边要跑主机,一边要跑虚拟机,存要求还是比较高的,这样才会比较流畅。 2. 安装VMWare 7.1.4。我的操作系统是Win7,VMWare的版本要新一点的,旧版本的VMWare在网络支持上比较差,由于要在虚拟机上下载Android源代码,没有网络是万万不行的。 3. 安装好VMWare后,接下来就安装Ubuntu系统了。我选择目前最新的版本ubuntu-11.04-alternate-i386,从网上查到的资料说,要编译Android源代码,Ubuntu 的最低版本是8.04。下载好后,安装时采用一直默认安装即可。 4. 安装Git工具。Android源代码采用Git工具来管理,与SVN相比,这是一种分布式的源代码管理工具,而SVN是集中式的源代码管理工具。要安装Git工具,在Ubuntu上执行以下命令即可: USER-NAMEMACHINE-NAME:~$ sudo apt-get install git-core gnupg 5. 安装Java SDK。在Ubuntu上执行以下命令: USER-NAMEMACHINE-NAME:~$ sudo add-apt-repository ppa:ferramroberto/java USER-NAMEMACHINE-NAME:~$ sudo apt-get update USER-NAMEMACHINE-NAME:~$ sudo apt-get install sun-java6-jre sun-java6-plugin USER-NAMEMACHINE-NAME:~$ sudo apt-get install sun-java6-jdk 6. 依赖的其它包。在Ubuntu上执行以下命令: USER-NAMEMACHINE-NAME:~$ sudo apt-get install flex bison gperf libsdl-dev libesd0-dev libwxgtk2.6-dev build-essential zip curl

android wifi驱动开发日记(一)

学习android wifi开发已经一周了,今天开始立帖,将每天的学习成果贴出来,以备以后查阅,从framework 到wpa_supplicant的适配层(wifi.c)网上介绍的帖子很多,而且本身也并不复杂,其中framework部分需要注意的是wifiService和wifiMoniter两部分,这两快一个是转发AP的CMD另一个是接收来自 wpa_supplicant的CMD。他们与本地库的连接都是通过JNI方法,具体实现方法在 android_net_wifi_Wifi.cpp中。在这个文件中可以大致看出AP会给wpa_supplicant下哪些命令。这些命令通过wifi.c的wifi_command发送给wpa_supplicant,在发送命令的过程中实际是调用wpa_ctrl_request 来完成命令发送的,wpa_ctrl_request是通过socket的方式与wpa_supplicant进行通信的,然后通过wpa_ctrl_recv来接收来自wpa_supplicant的命令,并返回标识给wifi_wait_for_event。 但是命令发到wpa_supplicant后的流程网上提到的资料就非常少了,不过由于wpa_supplicant是一个标准的开源项目,已经被移植到很多平台上,它中间的过程我暂时还没有去细看。比较关心的是 wpa_supplicant在接收到上层的命令后是怎么将命令发给DRIVER的,DRIVER在接收到命令后的解析的动作以及之后调用驱动功能函数的流程以及驱动对寄存器控制的细节。由于需要注意代码保密,之后不会提及具体使用了哪块WIFI芯片也不会提及此WIFI DRIVER是在什么平台什么产品。 先贴一张wpa_supplicant的标准结构框图:

相关主题
相关文档
最新文档