申请标题:申请会员ID:攀登的蜗牛
1、申 请 I D:攀登的蜗牛
2、个人邮箱:kuailedi2015@163.com
3、原创技术文章:Android内核研究之--HAL层学习
注:以帖子内容,可能达不到精华帖,但是本人对热衷内核研究,希望加入到破解论坛与跟多但牛一起交流学习
Android内核学习之番外篇一 -----HAL学习总结与计划1. 学习前言本篇博客的学习是基于老罗的Android之旅的书和博客的。关于这个地方的学习之前曾经花时间看过一遍,并且跟着走了一遍,但是中途因为碰到问题没有解决,导致很多地方都跳过去了。这一次算是全部走完了整个流程,从底层的驱动编写到顶层app访问虚拟设备成功完整的跟着学习做了一遍。虽然这次也有不少的挫折,但是还好都一一解决了。这里想记录一下学习的过程,并且将后面需要自完善部分也提出来,让自己更深入的理解这一块。 2. HAL学习编译步骤(1) 编写Android系统的内核驱动程序 其实内核驱动的编写有一定的格式,只要是有固定格式的编写应该都不难,但是无奈我的C基础比较薄弱,看LDD(Linux Device Drivers)的时候也基本上是囫囵吞枣(这个词我用了好多次,汗颜)了。但是以前一些固定的语法不懂,现在最起码能看懂了。但是能达到编写内核驱动的功力我还是远远不够。只是短期我也没那么多奢求了,只希望能把Android底层摸头就可以了。 这里的驱动并不是为真正的硬件编写,而是为一个虚拟设备----一个4字节的寄存器设备----编写的驱动。 在XXX/kernel/common/drivers 目录下新建驱动文件,按照驱动的格式写好驱动。然后make即可将驱动编译到内核中去。 传统的硬件读写打开关闭方法: 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); (2) HAL层模块访问内核驱动程序 按照Android硬件抽象层规范的要求,分别定义模块ID、模块结构体以及硬件接口结构体。 疑问:HAL层的模块是如何同内核的驱动进行交互的,在这里没看明白。 关于这篇文章有个问题没想清楚:这里的HAL模块访问内核驱动,但是是在什么地方涉及到与内核驱动的交互呢? 比如在hello_set_val 方法的实现中,有write(dev->fd, &val, sizeof(val));这样一句代码,这里的write是不是就是对应着HAL系列关于内核驱动编写那篇文章中的 .write =hello_write,也就是这里的write就是调用了内核驱动中hello_write这个方法从而达到HAL模块访问内核驱动模块?? (3) Runtime Lib层JNI接口访问HAL 通过编写JNI方法,向上层提供jni接口供java访问,方法写在如下的类中:com_android_server_HelloService.cpp 其中包括三个方法: static void hello_setVal(JNIEnv* env, jobject clazz, jint value) static jint hello_getVal(JNIEnv* env, jobject clazz) static jboolean hello_init(JNIEnv* env, jclass clazz) static const JNINativeMethod method_table[] int register_android_server_HelloService(JNIEnv *env) 这些方法通过device来调用HAL模块的方法与内核驱动直接交互。 这个类以及类中的方法和类中的变量类型都有严格的命名方式,类名按照com_android_server_XXX方式命名,变量都是按照JNI规定的方式命名变量。 然后在onload.cpp中将JNI的方法注册到内部。 (4) Frameworks增加硬件访问服务 在下面目录下床架可以与上面的JNI交互的程序: frameworks/base/core/java/android/os 1. package android.os; 2. 3. interface IHelloService { 4. void setVal(int val); 5. int getVal(); 6. }
首先定义AIDL文件,AIDL是android用来进行远程接口调用的语言模式,android内部可以根据AIDL的定义生成stub类和代{过}{滤}理类,也就是服务端和客户端进程分别可以调用的类,然后这两个类通过binder的机制进行交互通信,也就达到了线程间的通信的目的。 然后定义一个service继承自stub接口,然后接口的实现通过navtive的方法调用上面所涉及的JNI方法,然后通过JNI方法与内核驱动的交互来访问设备寄存器(我们在上面涉及的虚拟设备)。 这里的AIDL要用hide来标示,否则编译不用过。 (5) Application层访问frameworks层的硬件服务 1. helloService = IHelloService.Stub.asInterface( 2. ServiceManager.getService("hello"));
通过面代码获得上一步注册的HelloService接口,然后在app中调用方法的时候就通过方法中的native访问了运行时层的相关JNI方法,JNI方法通过device调用HAL层的函数与内核模块交互,这样就完成了app==》frameworks==》运行时库==》HAL层模块==》内核驱动==》硬件设备,这一整个过程的流转。 (6) 留白,未完待续…… 3. 总结其实,这个系列虽然是顺利走完了,但是很多内容还是不能融会贯通,我觉得可以通过binder的方式进行改造这个实例,如果改造成功的话说明我算是有个一知半解了,如果改造不成功,那就说明还有很多东西没走通。这个也就是我下面的计划:通过binder的形式改造HAL系列模块,完成从APPèframeworksèRuntime LibèHALè内核驱动è虚拟设备的流转。 看了这么久的资料,自己能整理了一下,感觉硬伤还是很多,主要是自己的积累不够吧。越这样越发佩服这些系列博客的大牛,能定下来学习并整理出这么好的资料给我们指导。我想绝大多数人很难再学得这么深入,有整理出这么高级的材料来了。他们也算是这个方面的巨人了吧。牛顿说他取得那么大的成就是因为站在了巨人笛卡尔的肩上。有人说这是一种谦逊,也有人说这是他在挤兑笛卡尔。但是有一个问题对我等凡人是至关重要的,那就是如何爬上巨人的肩膀上。要想达到一定的高度,只看书只弄懂了还远远不够,还要自己去实践去验证,要牢记知易行难。这样才算是一步一个脚印的往上走。其实经验并不能传授,我们走的更快也仅仅是因为前人的指引下我们少走了很多弯路,但是要达到一个高度只有不断的再弯路中迂回前进,盘旋上升。 继续努力,Keep moving!!!
|