7月19日-----20日学习工作记录1.资料下了Android技术内幕那本书,貌似不错,除了硬件抽象层那一张,其它的也要抽空看一下。不错的HAL层分析的网址是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,同样鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再发布(作为开源或商业软件)。需要满足的条件:1.需要给代码的用户一份ApacheLicense2.如果你修改了代码,需要在被修改的文件中说明。3.在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标,专利声明和其他原来作者规定需要包含的说明。4.如果再发布的产品中包含一个Notice文件,则在Notice文件中需要带有ApacheLicense。你可以在Notice中增加自己的许可,但不可以表现为对ApacheLicense构成更改。ApacheLicense也是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。3.HAL简介3.1AndroidHAL存在的原因主要有:1.并不是所有的硬件设备都有标准的linuxkernel的接口2.KERNELDRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方式绕过GPL。3.针对某些硬件,An有一些特殊的需求3.2现有HAL架构由PatrickBrady(Google)在2008GoogleI/O演讲中提出的两种HAL架构比较目前存在两种HAL架构,位于libhardware_legacy目录下的“旧HAL架构”和位于libhardware目录下的“新HAL架构”。两种框架如下图所示。libhardware_legacy是将*.so文件当作sharedlibrary来使用,在runtime(JNI部份)以directfunctioncall使用HALmodule。通过直接函数调用的方式,来操作驱动程序。当然,应用程序也可以不需要通过JNI的方式进行,直接加载*.so(dlopen)的做法调用*.so里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。现在的libhardware架构,就有stub的味道了。HALstub是一种代理人(proxy)的概念,stub虽然仍是以*.so檔的形式存在,但HAL已经将*.so档隐藏起来了。Stub向HAL提供操作函数(operations),而runtime则是向HAL取得特定模块(stub)的operations,再callback这些操作函数。这种以indirectfunctioncall的架构,让HALstub变成是一种包含关系,即HAL里包含了许许多多的stub(代理人)。Runtime只要说明类型,即moduleID,就可以取得操作函数。对于目前的HAL,可以认为Android定义了HAL层结构框架,通过几个接口访问硬件从而统一了调用方式。Android的HAL的实现需要通过JNI(JavaNativeInterface),JNI简单来说就是java程序可以调用C/C++写的动态链接库,这样的话,HAL可以使用C/C++语言编写,效率更高。3.3.HAL的实现HAL实际就是一个硬件抽象层的框架,其硬件设备的具体操作由对应的stub进行简介回调。HAL位于以下两个文件中。Hardware.c(libhardware)Hardware.h(libhardware\include\hardware)Hardwaer.h中定义了三个重要的结构体structhw_device_tstructhw_module_tstructhw_module_methods其中hw_device_t表示硬件设备,存储了各种硬件设备的公共属性和方法。如果要移植或者添加新设备,那么都需要使用该结构体进行注册,其中的tag必须初始化。代码如下:结构体hw_module_t在进行加载的时候用于判断属于哪一个module。代码如下:结构体hw_module_methods_t用于定义操作设备的方法operations,这里定义了一个打开设备的方法open。代码如下:下面分析如何获得HALstub,加载module时,可以调用hardware.c中的hw_get_module函数来获取HAL。在这个函数中,Android系统首先在系统的属性中查找硬件定义,然后通过该函数的参数id和查找到的模块路径(path)夹在形影的硬件HAL的特定模块so库文件。如果在系统属性中未定义硬件属性,则使用默认的硬件HAL对应模块的so库文件。其中property_get函数将根据定义的硬件配置查找对应的模块及其路径。然后调用load函数加载。下面给出hw_get_module()代码:这段代码就是查找我们硬件匹配的模块,然后将该库的路径放到path中,最后加载该路径对应的库。(sprintf用法)其中的property_get函数最终会获得variant_keys中的ro.hardware属性。我们可以在main函数中通过get_hardware_name()函数获得hardware的值(该函数可以获得当前Android系统运行的硬件信息。首先把数据放入hardware数组,然后通过snprintf()函数构建so库文件路径,这样就可以直接调用dlopen来打开。加载了so库文件后,就可以操作具体的硬件设备。Android提供了一些实现接口,它们位于hardware/libhardware/include/hardware中,比如vibrator。(Androidadb不错的网站:)4.Androidvibrator实现4.1HAL层Vibrator就是振动器,在Android诸多应用中都有应该,比如短信的震动提醒,以及很多游戏中,这给用户带来了更真实的体验。对于振动器的HAL层其实是非常简单的,之前因为我并没有理解HAL层与上层的关系,所以盲目的去看了那几个代码,在学习了HAL层与上层关系的相关知识后,又从新去看了老师给的几个代码。关于HAL层的代码位于:Vibrator.c(libhardware_legacy\vibrator)Vibrator.h(libhardware_legacy\include\hardware_legacy)实际上这两个代码就是定义了两个函数的接口,上层可以调用该接口对振动器进行操作。对于振荡器来说,操作无非就是打开振动器,关闭振动器。这里的实现也比较简单。第一次看的时候因为没有搞明白timeout_ms所以导致下面的代码没怎么理解。这里的timeout_ms实际就是打开振荡器持续的时间。其实现是通过sprintf()和write(),理解下面代码的话也就是说如果传入参数为0的话,其实就是关闭。而非0的话这里的由于执行这两个函数的时候需要话费一定的时间,这时候vibrator实际就在工作,从而达到打开vibrator的作用。return的条件判断语句就是说如果我没有出错的话就返回0,出错就为-1,这只是传回一个返回值用于监测执行情况,而实际上与打开关闭无关(理解的偏差也主要是在这里,当时以为是用返回值来控制打开与关闭)。然后vibrator.c文件中还定义了监测振荡器是否存在的函数。比较简单。下面给出代码。首先根据QEMU_HARDWARE宏来判断当前设别是否是模拟器,这里不从说明下,如果检测到是模拟器的话就直接调用,qemu_check()函数来进行监测,否则则代开该设备,监测到失败就返回0,成功就返回1。宏THE_DEVICE定义了设备接口文件路径。4.2jni层JNI简介:JNI(javaNativeInterface),即java本地接口,是为java编写本地方法和jvm嵌入本地应用程序的的应用程序接口。首要的目的是在给定的平台上采用JAVA通过JNI调用本地方法,而本地方法是以库文件的形式来存放的(windows平台是dll文件,在unix机器上则是以so文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法。有关vibratorjni层的代码位于:com_android_server_VibratorService.cpp(base\services\jni)下面给出代码并简单分析。这里其实就是对在HAL层的几个方法在这里进行封装。然后下面调用register_android_server_VibratorService()函数将这几种方法封装成下面的类com/android/server/Vibratorservice,最终我们在上层可以直接继承这个类,并调用封装好的这几个方法,从而实现了对于实际硬件的操作。学习jni不错的日志