Android 深度探索(3)

第八章 让开发板发出声音:蜂鸣器驱动

linux驱动的代码重用有很多种方法。可以采用标准C 程序的方式。将要重用的代码放在其他的文件(在头文件中声明〉中。如果要使用某些功能, include 相应的头文件即可〈这.方式称为静态重用〉。也可以使用另外一种动态重用的方式,也就是一个Linux 驱动可以使用另外一个Linux驱动中的资源(函数、变量、宏等)。如果Linux 驱动的代码不多,将所有的代码都放到一个文件中并没有什么不妥,但对于复杂的Linux 驱动,就需要使用多个源代码文件存放不同的功能代码,这样做有利于代码分类和管理。当然,如果Linux 驱动要使用第三方的源代码, 那么就不得不编译多个源代码文件,最终便成.ko 文件或编译进Linux内核。C 或C++语言中编译多个源代码文件时,如果a.c 使用了 b.c 文件中的函数,需要在a.c 文件中使用 extern 预先定义b.c中的函数, extern 的作用就是告诉编译器该函数的函数名、参数个数、参数类型和返回值类型。这些信息对于将a.c 编译成a.o已经足够了。等到将a.o 和b.o 链接成可执行文件或程序库时,编译器再到b.c中寻找函数的具体要现。也就是说, extern 只在编译阶段起作用。除此之外,还可以使用b.h 文件定义b.c 中的函数,然后在a.c中包含b.h 文件。对于有些C/C++编译器,可以省略extern 关键字。不过为了更通用,建议还是加上extern。

代码重用分为静态和动态两种。另外一种代码共享的方式:模块依赖,也称为导出符号。如果只能用一句话解释如何利用导出符号实现代码共享,这句话就是“在一个驱动模块里使用另一个驱动模块里的被导出的符号(常量、变量、函数等)”。1.由于Linux 驱动模块的初始化函数进行了某些操作而崩溃,从而导致初始化函数无法正常返回。这种情况的表现是当前Linux 驱动模块没被任何其他的Linux驱动模块使用,但却显示已经被引用了一次了一次。2.在使用rmmod 命令卸载Linux 驱动时,系统会调用卸载函数,只有卸载函数成功返回肘, Linux 驱动才会被翻载。如果卸载函数被阻塞(可能是死循环、并发等情况引起的阻塞), rmmod 命令也会被阻塞. 也就是说永远不会执行到卸载Linux 驱动模块的代码。这种情况的表现是一执行rmmod 命令就会停在那不动了,永远也不会返回到系统的操作提示符。

首先看第1 种情况。这种情况的关键是引用计数器的值和引用者不一致。实际上引用者是不存在的,因此,只需要将当前的Linux 驱动模块的引用计数器清零即可。修改引用计数器可以使用下面两个函数。

// 使module 指向的Linu x 驱动模焕的引用计数器加l ,成功返回1 ,失败返回0。

static inl 立ne int try_m。dule_get(struct module *module)

// 使module 指向的Linux 驱动模块的引用计数器减1。

extern void modul e_put (struct module *module);

第2 种情况的问题根源就是卸载函数,因此,只要将原来的卸载函数替换成一个空的卸载函数即可。

第九章 硬件抽象层:HAL

HAL ( Hardware Abstraction Layer,硬件抽象腔,〉是建立在Linux 驱动之上的一套翻字库。这套程序库并不属于Linux 内核,而是属于Linux 内核层之上的应用层。Google 为Android 增加HAL 的主要目

的除了尽量避免应用程序直接访问Linux 驱动外,还有一个重要原因,那就是保护“私人财产”。对于那些既想发布基于Android的Linux 驱动程序,又不想将核心业务逻辑公开的企业或个人,简直就是福音。

在传统的Linux系统中Linux驱动一般有两种类型的代码:访问硬件寄存器的代码和业务逻辑代码。对于访问硬件寄存器的代码,并没有什么秘密可言,因为这都是调用的Linux 内核的标准函数(ioread32 、iowrite32 等)进行的标准操作。而Linux 驱动的业务逻辑部分对击有些企业或个人并不想将源代码公开。尽管这些Linux 驱动都是免费给用户使用的,但由于这些Linux 驱动的实现涉及一些技术专利或商业秘密,如果公开源代码会有很大麻烦。但作为Linux.驱动,又不得不公开源代码。这是由于Linux 内核采用了GPL 协议,而GPL 协议要求所有使用基于GPL 协议的源代码的程序必须开源(由于Linux 驱动属于Linux 内核的一部分,因此Linux 驱动必须开源)。

总而言之,Google 为Android加入HAL主要有如下的目的:

1.统一硬件的调用接口。由于HAL 有标准的调用接卧,所以可以利用HAL屏蔽Linux 驱动复杂、不统一的接口。

2.解决了GPL版权问题。由于Linux 内核基于GPL协议,而Android 基于Apache Licence 2.0 协议。因此Google 玩了个“穿越”将原本位于Linux驱动中的敏感代码向上移了一个层次。这样这些敏感代码就摆脱了GPL 协议的束缚 。那些不想开源的Linux驱动作者也就没必要开源了。

3.针对一些特殊的要求。对于有些硬件,可能需要访问一些用户空间的资源,或在内核空间不方便完成的工作以及特殊需求。在这种情况下,可以利用位于用户空间的HAL 代码来辅助Linux驱动完成一些工作。

Google 为了满足这些不想开源的Linux 驱动作者的要求,在Android层次结构中的系统运行库层增加了一个HAL。HAL 并不是Linux 内核的一部分,而是位于Android的系统运行库层,而Android采用了Apache Licence2.0协议发布,Apache Licence2.0协议并未要求使用基于Apache Licence2.0协议的源代码的软件也必须开源。由于HAL属于Android的一部分,自然也不必开源了。

接下来是应用LED驱动的移植来演示支持HAL的linux驱动程序,让我们初步了解其步骤。

*编写调用HAL 模缺的Service

1.由于JNI 会用到很多C++代码,因此, LedHalService.cpp 不能改成LedHalService.c。

2.LedHalService.cpp 文件中引用了leds_hat.h头文件。该文件属于HAL 模块的源代码文件,己在Android.mk 文件中指leds__hat.h 文件所在的路径( hardware/leds_hal),在Android.mk 中指定的都属于系统路径,因此在include 该文件时要用尖括号(<...〉)。

3.JNI 方法在默认情况下有一定的命名规则(Java_packagename_classname_methodname),但可以通过RegisterNatives 自定义则JNI方法。该方法的最后一个参数需要指定要注册的JNI函数的个数。

4.利用slieof(methods)/sizeof(methods[0]计算methods数组长度,由于数组的每一个元素占用的字节个数是相等的

(JNINativeMethod类型,由3个指针组成,32位系统和64位系统每个数组元素占的字节数分别为12和24)。因此用整个数组占用的

字节数除以每一个数组元素占用的字节数(一定会被整除的)就是数组的长度。

5.methods数组的元素类型是JNINativeMethod。

注意:1.HAL 模块库文件的存放路径有两个: /system/lib/hw 和/vendor/lib/hw 。hw_get_ module 函数会先从/system/lib/hw 目录根据库文件命名规则寻找库文件。如果/system/lib/hw 目录中未找到库文件, hw_get_ module 会按同样的规则在/vendor/lib/hw 目录中寻找。

2.HAL 模块库文件的命名规则是ID.suffix.so。其中TD 通过hw_get_ module 函数的id 参数指定。suffix (后缀)通过属性文件指定。

3.hw _get_module 会在Android 系统的属性文件中根据variant_keys 数组中定义的4 个key依次查找suffix 。如果未找到suffix ,使用默认的suffix (default )。

Android 系统的属性文件共有如下4个:

/default.prop ;

/system/build.prop;

/system/default.prop;

/data/local.prop .

Android 在启动时会自动装载这些属性文件。如果在多个属性文件中都定义了同一个Key 和Value,那么只用第一个Key 被获取。例如,在/default.prop 文件中定义了ro.product.board 的值为abc,而在/system/build.prop 文件中定义了ro.product.board 的值为xyz。那么hw_get_ module 函数会把/default.prop 文件中的abc 作为HAL 模块库文件的后缀,而不会再读取/system/build.prop 文件中的xyz。

在Android系统中使用Linux 驱动有两种方式。一种就是通过传统的方式直接与Linux 驱动交互。例如,直接读写设备文件的数据。另外一种是Android特有的,就是通过HAL 模块 。HAL 模块本质上就是通过Linux 共享库(.so)与Linux驱动交互,然后应用程序再访问Linux共享库。早期的HAL模块由应用程序直接按访问Linux共字库的方式调用。而高版本的Android 系统为HAL增加了Stub 。换句话说,就是为每一个HAL共享库指定一个ID, 再利用这个ID 配合一定的规则找到Linux 共字库,这样Linux 共字库更换文件名,移动位置都很方便(因为HAL 共享库的路径和文件名都不是定死的),Google也建议使用Stub 的方式编写HAL模块。

第十章 嵌入式linux的调用技术

printk 函数在控制台(也称为终端)显示消息是通过/dev/console 设备文件实现的,该设备文件只在字符界面的控制台下才起作用p 所以printk 函数只有用在字符界面的控制台上才能正常输出消息。printk 函数在前面的章节己多次使用过。该函数的用法与printf 函数类似,只不过printk函数运行在内核空间, printf函数运自行在用户空间。也就是说,像Linux 驱动这样的Linux内核程序只能使用printk函数输出调用信息。

在Linux 文件系统中, /proc 经常被用来作为内核空间与用户空间进行数据交互的工具。/proc文件系统的行为方式与设备文件系统(/dev )类似。/proc 是虚拟文件系统,也就是说了,/proc 并不

是真正的文件系统,而是内存映射。所有读写/proc操作都是对内存的读写。 所以读写/proc 文件系统的速度要远比读写/dev 文件系统的速度快。因此,/proc 文件系统也可作为Linux 驱动与用户空间程序交互的工具。有很多系统信息就是通过/proc 文件系统由内核空间的程序向外界提供的。

*在Linux 系统中提供了一类工具。通过这些工具,可以逐行跟踪程序的代码,就好像可视化开发工具的step into 和step over 一样。

这些工具包含用于调试用户空间程序的gdb、gdbserver 和调试内核空间程序的kgdb。

时间: 2025-01-13 15:07:19

Android 深度探索(3)的相关文章

Android深度探索HAL与驱动开发 第四章

Android深度探索HAL与驱动开发 第四章 源代码的下载和编译 读书笔记 一.下载编译和测试Android源代码 1.配置Android源代码下载环境 创建一个用于存放下载脚本文件的目录(可将该文件放到任何一个目录在这里使用-/bin) # mkdir ~/bin # PATH=~/bin:$PATH 2.下载repo脚本文件(用于下载Android源代码) # curl htttps://dl-ssl.google.com/dl/googlesource/git-repo/repo> ~/

Android深度探索HAL与驱动开发 第三章

Android深度探索HAL与驱动开发 第三章 Git使用入门 读书笔记 Git是对源代码进行管理的软件. 一.安装Git # apt-get install git # apt-get install git-doc git-emall git-gui gitk 用以下命令控制Git: # apt-get install git-core # apt-get install git-doc git-svn git-email git-gui gitk 二.查看Git文档 查看git-check

Android深度探索(卷1)HAL与驱动开发学习笔记(2)

Android深度探索(卷1)HAL与驱动开发学习笔记(2) 第二章搭建Android开发环境 书中介绍了两种JDK的安装方法, 方法一: 从官网下载JDK并进行配置,解压后在终端打开profile文件来设置PATH环境变量(# soure /etc/profile),打开profile文件后输入下面的内容 export PATH=.:developer/jdk6/bin:$PATH 保存profile文件以后,有两种方法可以重新加载profile文件. 1.# sourse  /etc/pro

《Android深度探索》第十章心得体会

<Android深度探索>第十章讲的是嵌入式Linux的调试技术.对于复杂的Linux驱动及HAL等程序库,需要使用各种方法对其进行测试.printk函数的用法和printf函数类似,只不过printk函数运行在内核空间,printf函数运行在用户空间.也就是说,像Linux驱动这样的Linux内核程序只能使用printk函数输出调试信息.在Linux文件系统中,/proc经常用来作为内核空间和用户空间进行数据交互的工具./proc文件系统的行为方式和设备文件系统(/dev)类似./proc是

Android深度探索HAL与驱动开发 第二章

Android深度探索HAL与驱动开发 第二章 搭建Android开发环境 读书笔记 一.Android底层开发需要的工具 1.JDK6或以上版本 2.Eclipse3.4或以上版本 3.ADT(用于开发Android的应用程序) 4.CDT(用于开发Android NDK程序) 5.Android SDK 6.Android NDK 7.交叉编译环境 8.Linux内核源代码 9.Android源代码 10.用于调试开发板的串口工具:minicom 二.安装JDK 下载JDK后在终端输入 #

Android深度探索总结

Android深度探索前四章总结 通过这几章的学习真实体会到“移植”的概念:为特定设备定制Android的过程,但是移植的过程中开发最多的就是支持各种硬件设备的Linux驱动程序,本章对Android和Linux做了总体介绍.接着介绍了Android的四层架构:Linux内核:C/C++代码库:Android SDK API;应用程序.又引入Android移植,Android移植包括两部分:应用移植,系统移植.而且为硬件平台添加新的模块,必须为此模块添加一个新的驱动程序,或者修改原来的程序. 学

《Android深度探索》第五章心得体会

<Android深度探索>第五章讲的是搭建S3C6410开发板的测试环境.S3C6410开发板是由三星公司生产的一款开发板产品,具有许多优点.本书的研究就是基于这块开发板的. 搭建环境需要先安装串口调试工具,然后烧入Android系统. 1. 安装串口调试工具:minicom, 第1步:输入命令 insmod | grep usbserial命令检测当前系统是否支持USB转串口: 第2步:输入命令apt-get install minicom命令安装minicom: 第3步:输入minicom

《Android深度探索卷一》第一章Android系统移植与驱动开发概述。

<Android深度探索>第一章讲的是Android系统移植与驱动开发概述.这一章节将对Android以及Linux驱动做一个总体的介绍. Android是一个非常优秀的的嵌入式操作系统.经过几年的发展和演进,Android已经形成了非常完善的系统架构.Android的系统架构分为四层,如下图 Android移植可分为两部分:应用移植和系统移植. Android系统移植是指让Android操作系统在某一个特定硬件平台上运行.使一个操作系统在特定硬件平台上运行的一个首要条件就是该操作系统支持硬件

android深度探索第一章

Android深度探索HAL与驱动开发的第一章学习了android系统移植与系统开发详述. 正如书上的导言所说,,android已经成为当前智能手机操作系统的老大.所以其重要性可想而知,其学习的意义非比寻常.其发展的迅速,很大程度上取决于任何人都可以利用android的源代码定制完全属于自己的嵌入式系统,而不需要向Google交钱.而由于android原生的代码支持的设备不多,因此,要想在自己的设备(包括手机.智能电视.平板等)上完美运行android,就需要另外一些开发程序,使得android

Android深度探索第四章总结

Android深度探索第四章主要是源代码的下载和编译.要下载Android源代码首先需要配置Android源代码下载环境(1.创建一个用于存放下载脚本文件的目录:2.下载repo脚本文件:3.创建用于存放Android晕代码的目录:4.初始化:5.开始下载Android源代码).介绍了Android源代码目录结构(/bootable这个目录下存放 android 部分启动相关代码,包括 android 的 recovery模式,一般用于进行 OTA 升级,由 C++ 编写,可以看到用于显示的ui