前一章节,参考了‘老罗的Android之旅’,基于Android6.0完成了从APP到内核的一整条通路的梳理,了解了一些基本的通信原理,API调用,以及相关进程的启动,但是很多人对Android按下电源键后,到UI加载的这一整个过程还不是很了解,接下来就让我们一起来解开这神秘的面纱,看看Android是如何启动的。
JAVA层APP访问Framework服务
前面一章我们已经写好了Framework的service,并提供了service的读写接口,即getVal( )和setVal( )两个函数,这一章,我们就要来学习如何写一个APK,通过这两个service的接口来实现hello驱动寄存器值的读写。
由于直接手写一个Android应用程序还是比较困难的,因此这里我还是需要借助IDE的环境,这里我们使用现在谷歌大力推广的Android Studio来进行应用程序的开发,当APK写完后,把应用程序的源码拷贝到packages\experimental中,并通过修改Android.mk来实现APK的编译.
Framework提供接口访问硬件
上一章,我们理解了如何写一个JNI方法来访问HAL层的接口,这个JNI的方法最终是被Android Framework来进行调用,Android Framework最终又被Android的应用软件进行调用,从而实现从可视应用程序访问驱动寄存器的通路。本章我们一起来学习如何在Android Framework层来写接口供可视应用程序访问,并且访问JNI的接口。
1.新建AIDI代理
服务一般是运行在一个独立的进程中来为各个应用程序提供服务,因此应用程序需要访问服务的接口,就需要通过代理来试下,Android中主要通过AIDI代理实现。
创建方法:
cd /frameworks/base/core/java/android/os
vim IHelloService.aidl
IHelloService.aidl定义了IHelloService接口:
HAL层写JNI方法提供Framework访问接口
前面几张我们理解了如何在kernel中写驱动程序,如何访问这个驱动,在HAL层如何读写hello驱动的寄存器值,接下来我们想从App层(一个apk程序)能对hello驱动的寄存器值进行读写操作,但是APP层使用的是JAVA语言,HAL层以及kernel使用的是C\C++语言进行编写,我们如何才能进行跨语言的调用呢? Android给我们提供了一个很好的方法JNI(Java Native Interface)来进行调用。
Android的应用程序使用java编写,Java类编译为Dex型式的Bytecode之后,必须靠Dalvik虚拟机(VM: Virtual Machine)来执行。在执行Java类的过程中,如果Java类需要与C组件沟通时,VM就会去载入C组件,然后让Java的函数顺利地调用到C组件的函数。此时,VM扮演着桥梁的角色,让Java与C组件能通过标准的JNI介面而相互沟通。
我们这里JAVA应用程序将会通过JNI方法来调用硬件抽象层接口,来实现对寄存器值的读写操作。
HAL层访问Linux内核驱动程序
上一章学习了从C空间访问Linux内核驱动程序,这一章我们一起来学习如何在硬件抽象层中增加硬件模块来访问内核驱动程序。本章还是跟上一章一样,通过传统设备/dev/hello来连接硬件抽象层模块和内核驱动程序。
1.进入到/hardware/libhardware/include/hardware目录
新建hello.h
1 | #ifndef ANDROID_HELLO_INTERFACE_H |
这里定义了模块ID—hello,模块结构体,硬件接口结构体。
C空间增加可执行程序访问硬件驱动
上一章我们学习了如何在内核中写驱动程序,我们创建了三种不同的文件节点供用户来访问,分别是传统设备/dev/hello、proc文件系统/proc/hello和devfs系统属性访问/sys/class/hello/hello/val。但是我们没有去真正的验证程序的有效性,这一章我们一起来学习一下,如何在用户C空间写一个C的程序来访问hello驱动。
用户C空间的进程都被放在/system/bin中,例如我们常用的logcat、logd、rild等进程都能在其中找到。
Tianger:~ getianger$ adb shell
root@android:/ # cd system/bin
root@android:/system/bin # ls
接下来开始来实现这个C的进程,我们把这个进程取名为hello。
在Android内核中编写硬件驱动
本章主要讲解在Android的内核中编译硬件驱动程序,由于没有明确的GPIO口控制,因此这里不涉及硬件部分,我们使用一个虚拟硬件设备,并实现读写接口。
由于我现在内核的知识点还比较浅,因此内核的部分只是作为参考,主要目的,是为了尝试从APK到内核的一条通路实现过程。详细的内核需要等以后把Framework相关的知识补充完整后,再进一步学习。
这里创建一个虚拟硬件设备,命名为hello,即内核驱动的名称也为hello,用来进行读写寄存器的值。
1.进入到kernel/driers,并新建hello文件夹
Tianger:~ getianger$ cd /Developer/Android/kernel/drivers/
Tianger:drivers getianger$ mkdir hello
Android硬件抽象层(HAL层)学习计划
Android的系统非常复杂和庞大,底层以Linux为基础,上层采用带有虚拟机的JAVA层,通过JNI技术,将上下层打通。我们通常在网上看到的都是官方给出的经典四层架构图。从上到下分别是应用程序层、应用框架层、系统库和运行时库,Linux内核。但是我这里给出的图示多了一层为HAL层(硬件抽象层),这一层主要作用是对硬件设备的具体实现加以抽象.
Android6.0 系统源码下载及环境搭建
前段时间回顾了一下C和JAVA的一些基础和进阶书籍,接下来让我们真正进入Android系统源码的怀抱吧,我会根据一个月之前写的《Android取经之路–学习启动篇》的知识点一步步的往下进行分析及学习,最终的目的是希望完成一个中间件,能够完成其他service到Framework,最终能到Modem的相关操作。
我使用的环境为Windows + Ubuntu16.04虚拟机.
源码下载及环境搭建参考了 AOSP - 清华大学TUNA 镜像源
https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
C与指针-第十七章-队列
前面学习了堆栈的操作,本章主要来学习队列的相关操作。
队列的特点:
1)先进先出(First in First Out FIFO)
例如排队等餐,先排的人拿到快餐后,离开这个队伍,后面一个人前进一位,新来的人在队伍的最后面加入
2)队列只允许在队首进行删除操作,队尾进行添加操作
队列的数据存储方式主要有下面两种方式:
1)动态数组存储
2)链表存储