【Android源码 栏目提醒】:网学会员,鉴于大家对Android源码 十分关注,论文会员在此为大家搜集整理了“Android系统开发入门 - 编程语言”一文,供大家参考学习!
Android系统开发入门 版本1.0 日期2010年11月 作者胡章焱 zyhuingenic.cn 注相信大家都知道
Android的APP的是用Java写的运行在Dalvik虚拟机上还有
Android的系统是基于Linux Kernel 2.6的。
那么要想深入了解
Android系统的各种细节当然少不了Linux Kernel的知识了。
阅读本文需要具备一定的C和JAVA语言基础并且对linux系统有一定了解。
最好对C也有一定的了解。
本文的内容是基于
Android2.2版本平台以一个设备将系统内存模拟成一个带4字节寄存器的设备为例从底层驱动到中间件到上层应用程序全过程的代码实现。
所编写的代码例子都可以在
Android模拟器进行运行。
但由于
android.git.kernel.org在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中编写硬件驱动程序.............................4 二、 在
Android系统中增加C可执行程序来访问硬件驱动程序。
.....................14 三、 在
Android硬件抽象层HAL增加接口模块访问硬件驱动程序.................17 四、 在
Android系统中编写JNI方法在应用程序框架层提供Java接口访问硬件 22 五、 在
Android系统的应用程序框架层Framework增加硬件服务接口...........26 六、 在
Android系统中编写APP通过应用程序框架层访问硬件服务.................28 学习完这篇文章相信大家对
Android系统开发就会有一个更深刻的认识了敬请关注。
一、 在
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目录 zyhuubuntu-50:/work/kernel cd drivers/ zyhuubuntu-50:/work/kernel/drivers mkdir hello 二在hello目录中增加hello.h文件 hello.h ifndef _HELLO_
ANDROID_H_ define _HELLO_
ANDROID_H_ include ltlinux/cdev.hgt include ltlinux/semaphore.hgt define HELLO_DEVICE_NODE_NAME quothelloquot define HELLO_DEVICE_FILE_NAME quothelloquot define HELLO_DEVICE_PROC_NAME quothelloquot define HELLO_DEVICE_CLASS_NAME quothelloquot struct hello_
android_dev int val struct semaphore sem struct cdev dev endif 这个头文件定义了一些字符串常量宏在后面我们要用到。
此外还定义了一个字符设备结构体hello_
android_dev这个就是我们虚拟的硬件设备了val成员变量就代表设备里面的寄存器它的类型为intsem成员变量是一个信号量是用同步访问寄存器val的dev成员变量是一个内嵌的字符设备这个Linux驱动程序自定义字符设备结构体的标准方法。
三在hello目录中增加hello.c文件这是驱动程序的实现部分。
驱动程序的功能主要是向上层提供访问设备的寄存器的值包括读和写。
这里提供了三种访问设备寄存器的方法一是通过proc文件系统来访问二是通过传统的设备文件的方法来访问三是通过devfs文件系统来访问。
下面是该驱动程序的实现。
我会对代码分段注释描述。
Hello.c /包含必要的头文件和定义三种访问设备的方法/??include ltlinux/init.hgt include ltlinux/module.hgt include ltlinux/types.hgt include ltlinux/fs.hgt include ltlinux/proc_fs.hgt include ltlinux/device.hgt include ltasm/uaccess.hgt include quothello.hquot /主设备和从设备号变量/ 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_openstruct inode inode struct file filp static int hello_releasestruct inode inode struct file filp static ssize_t hello_readstruct file filp char __user buf size_t count loff_t f_pos static ssize_t hello_writestruct 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_showstruct device dev struct device_attribute attr char buf static ssize_t hello_val_storestruct device dev struct device_attribute attr const char buf size_t count /定义设备属性/ static DEVICE_ATTRval S_IRUGO S_IWUSR hello_val_show hello_val_store / 定义传统的设备文件访问方法主要是定义hello_open、hello_release、hello_read和hello_write这四个打开、释放、读和写设备文件的方法/ /打开设备方法/ static int hello_openstruct inode inode struct file filp struct hello_
android_dev dev /将自定义设备结构体保存在文件指针的私有数据域中以便访问设备时拿来用/ dev container_ofinode-gti_cdev struct hello_
android_dev dev filp-gtprivate_data dev return 0 /设备文件释放时调用空实现/ static int hello_releasestruct inode inode struct file filp return 0 /读取设备的寄存器val的值/ static ssize_t hello_readstruct file filp char __user buf size_t count loff_t f_pos ssize_t err 0 struct hello_
android_dev dev filp-gtprivate_data /同步访问/ ifdown_interruptibleampdev-gtsem return -ERESTARTSYS ifcount lt sizeofdev-gtval goto out /将寄存器val的值拷贝到用户提供的缓冲区/ ifcopy_to_userbuf ampdev-gtval sizeofdev-gtval err -EFAULT goto out err sizeofdev-gtval out: upampdev-gtsem return err /写设备的寄存器值val/ static ssize_t hello_writestruct file filp const char __user buf size_t count loff_t f_pos struct hello_
android_dev dev filp-gtprivate_data ssize_t err 0 /同步访问/ ifdown_interruptibleampdev-gtsem return -ERESTARTSYS ifcount sizeofdev-gtval goto out /将用户提供的缓冲区的值写到设备寄存器去/ ifcopy_from_userampdev-gtval buf count err -EFAULT goto out err sizeofdev-gtval out: upampdev-gtsem return err / 定义通过devfs文件系统访问方法这里把设备的寄存器val看成是设备的一个属性通过读写这个属性来对设备进行访问主要是实现hello_val_show和hello_val_store两个方法同时定义了两个内部使用的访问val值的方法__hello_get_val和__hello_set_val/ /读取寄存器val的值到缓冲区buf中内部使用/ static ssize_t __hello_get_valstruct hello_
android_dev dev char buf int val 0 /同步访问/ ifdown_interruptibleampdev-gtsem return -ERESTARTSYS val dev-gtval upampdev-gtsem return snprintfbuf PAGE_SIZE quotdnquot val /把缓冲区buf的值写到设备寄存器val中去内部使用/ static ssize_t __hello_set_valstruct hello_
android_dev dev const char buf size_t count int val 0 /将字符串转换成数字/ val simple_strtolbuf NULL 10 /同步访问/ ifdown_interruptibleampdev-gtsem return -ERESTARTSYS dev-gtval val upampdev-gtsem return count /读取设备属性val/ static ssize_t hello_val_showstruct device dev struct device_attribute attr char buf struct hello_
android_dev hdev struct hello_
android_devdev_get_drvdatadev return __hello_get_valhdev buf /写设备属性val/ static ssize_t hello_val_storestruct device dev struct device_attribute attr const char buf size_t count struct hello_
android_dev hdev struct hello_
android_devdev_get_drvdatadev return __hello_set_valhdev buf count / 定义通过proc文件系统访问方法主要实现了hello_proc_read和hello_proc_write两个方法同时定义了在proc文件系统创建和删除文件的方法hello_create_proc和hello_remove_proc/ /读取设备寄存器val的值保存在page缓冲区中/ static ssize_t hello_proc_readchar page char start off_t off int count int eof void data ifoff gt 0 eof 1 return 0 return __hello_get_valhello_dev page /把缓冲区的值buff保存到设备寄存器val中去/ static ssize_t hello_proc_writestruct file filp const char __user buff unsigned long len void data int err 0 char page NULL iflen gt PAGE_SIZE printkKERN_ALERTquotThe buff is too large: lu.nquot len return -EFAULT page char__get_free_pageGFP_KERNEL ifpage printkKERN_ALERTquotFailed to alloc page.nquot return -ENOMEM /先把用户提供的缓冲区值拷贝到内核缓冲区中去/ ifcopy_from_userpage buff len printkKERN_ALERTquotFailed to copy buff from user.nquot err -EFAULT goto out err __hello_set_valhello_dev page len out: free_pageunsigned longpage return err /创建/proc/hello文件/ static void hello_create_procvoid struct proc_dir_entry entry entry create_proc_entryHELLO_DEVICE_PROC_NAME 0 NULL ifentry entry-gtread_proc hello_proc_read entry-gtwrite_proc hello_proc_write /删除/proc/hello文件/ static void hello_remove_procvoid remove_proc_entryHELLO_DEVICE_PROC_NAME NULL /定义模块加载和卸载方法这里只要是执行设备注册和初始化操作/ /初始化设备/ static int __hello_setup_devstruct hello_
android_dev dev int err dev_t devno MKDEVhello_major hello_minor memsetdev 0 sizeofstruct hello_
android_dev cdev_initampdev-gtdev amphello_fops dev-gtdev.owner THIS_MODULE dev-gtdev.ops amphello_fops /注册字符设备/ err cdev_addampdev-gtdevdevno 1 iferr return err /初始化信号量和寄存器val的值/ init_MUTEXampdev-gtsem dev-gtval 0 return 0 /模块加载方法/ static int __init hello_initvoid int err -1 dev_t dev 0 struct device temp NULL printkKERN_ALERTquotInitializing hello device.nquot /动态分配主设备和从设备号/ err alloc_chrdev_regionampdev 0 1 HELLO_DEVICE_NODE_NAME iferr lt 0 printkKERN_ALERTquotFailed to alloc char dev region.nquot goto fail hello_major MAJORdev hello_minor MINORdev /分配helo设备结构体变量/ hello_dev kmallocsizeofstruct hello_
android_dev GFP_KERNEL ifhello_dev err -ENOMEM printkKERN_ALERTquotFailed to alloc hello_dev.nquot goto unregister /初始化设备/ err __hello_setup_devhello_dev iferr printkKERN_ALERTquotFailed to setup dev: d.nquot err goto cleanup /在/sys/class/目录下创建设备类别目录hello/ hello_class class_createTHIS_MODULE HELLO_DEVICE_CLASS_NAME ifIS_ERRhello_class err PTR_ERRhello_class printkKERN_ALERTquotFailed to create hello class.nquot goto destroy_cdev /在/dev/目录和/sys/class/hello目录下分别创建设备文件hello/ temp device_createhello_class NULL dev quotsquot HELLO_DEVICE_FILE_NAME ifIS_ERRtemp err PTR_ERRtemp printkKERN_ALERTquotFailed to create hello device.nquot goto destroy_class /在/sys/class/hello/hello目录下创建属性文件val/ err device_create_filetemp ampdev_attr_val iferr lt 0 printkKERN_ALERTquotFailed to create attribute val.nquot goto destroy_device dev_set_drvdatatemp hello_dev /创建/proc/hello文件/ hello_create_proc printkKERN_ALERTquotSuccedded to initialize hello device.nquot return 0 destroy_device: device_destroyhello_class dev destroy_class: class_destroyhello_class destroy_cdev: cdev_delamphello_dev-gtdev cleanup: kfreehello_dev unregister: unregister_chrdev_regionMKDEVhello_major hello_minor 1 fail: return err /模块卸载方法/ static void __exit hello_exitvoid dev_t devno MKDEVhello_major hello_minor printkKERN_ALERTquotDestroy hello device.nquot /删除/proc/hello文件/ hello_remove_proc /销毁设备类别和设备/ ifhello_class device_destroyhello_class MKDEVhello_major hello_minor class_destroyhello_class /删除字符设备和释放设备内存/ ifhello_dev cdev_delamphello_dev-gtdev kfreehello_dev /释放设备号/ unregister_chrdev_regiondevno 1 MODULE_LICENSEquotGPLquot MODULE_AUTHORquotHuzhangyznquot MODULE_DESCRIPTIONquotFirst
Android Driver Helloquot MODULE_VERSIONquotV1.0quot MODULE_ALIASquotA Simple
Android Driverquot module_inithello_init module_exithello_exit 四在hello目录中新增Kconfig和Makefile两个文件其中Kconfig是在编译前执行配置命令make menuconfig时用到的而Makefile是执行编译命令make是用到的 Kconfig文件的内.