Android系统是有众多的子项目组成的。从编程语言角度来看,这些项目主要是使用Java和C/C++来实现的;从整体系统框架而言,分成内核层、硬件抽象层、系统运行库层、应用程序框架层以及应用程序层。
一、内核层
Android的底层是基于Linux操作系统的,主要使用包括核心和驱动程序两部分。
首先,避开了与硬件直接打交道。
其次,基于Linux系统的驱动开发可扩展性很强
Android内核是基于Linux 2.6内核的,这是一个增强内核版本,除了修改部分Bug外,还提供了用于支持Android平台的设备驱动。Android不但使用了Linux内核的基本功能,而且对Linux进行了改造,目的是实现更为强大的通信功能。android对linux下面内容做了增强:
1)硬件时钟(alarm)
2)内存分配与共享(Ashem)
3)低内存管理(low memory killer)
4)kernel调试
5)日志设备(LogCat)
6)android IPC机制(Binder机制Andoid一个特殊的驱动程序,具有单独的设备节点,提供进程间通讯的功能)
7)电源管理(power management)
主要的驱动如下所示:
1)显示驱动(Display Driver):常用基于Linux的帧缓冲(Frame Buffer)驱动。
2)Flash内存驱动(Flash Memory Driver)
3)照相机驱动(Camera Driver):常用基于Linux的v4l(Video for )驱动。
4)音频驱动(Audio Driver):常用基于ALSA(Advanced Linux Sound Architecture,高级Linux声音体系)驱动。
5)WiFi驱动(Camera Driver):基于IEEE 802.11标准的驱动程序
6)键盘驱动(KeyBoard Driver)
7)蓝牙驱动(Bluetooth Driver)
二、硬件抽象层
硬件抽象层(Hardware Abstract Layer,HAL), 是对Linux内核驱动程序的封装,是Android为厂商定义的一套接口标准,向上提供接口(把硬件驱动程序的调用封装成Stub),屏蔽底层的实现细节,进一步降低Android系统与硬件的耦合度。把对硬件的支持分成了两层,一层放在用户空间(User Space),一层放在内核空间(Kernel Space),其中硬件抽象层放在用户空间,而Linux内核驱动程序放在内核空间。把硬件抽象层和内核驱动整合在一起放在内核空间不可行吗?从技术实现角度看是可以的,然而从商业的角度来看,把对硬件的支持逻辑都放在内核空间,可能会损害厂家的利益。由于Linux遵循的是GPL协议,而Android开源项目基于Apache协议,前者在发布产品时,必须公布源代码,而后者无需发布源代码。如果把对硬件支持的所有代码都放在Linux驱动层,就意味着发布时要公开程序的源代码,也就意味着把硬件的相关参数和实现都公开了。因此android才把对硬件的支持分成硬件抽象层和内核驱动层,内核驱动层只提供简单的访问硬件逻辑,例如读写硬件寄存器的通道,至于从硬件中读到了什么值或者写了什么值到硬件中的逻辑,都放在硬件抽象层中去了,这样就可以把商业秘密隐藏起来。也正是由于这个分层的原因,android被踢出了Linux内核主线代码树中。因为Android放在内核空间的驱动程序对硬件的支持是不完整的,把Linux内核移植到别的机器上去时,由于缺乏硬件抽象层的支持,硬件就完全不能用了,这也是为什么说Android是开放系统而不是开源系统的原因。
三、系统库和运行时库
1、程序库
对于框架层而言,核心类库就是它的“贤内助”。每一次Android系统升级,能看到的都是框架层SDK的变迁,增加了新的功能,提供了新的接口。而在这些新功能的背后,核心类库都是居功至伟。
核心类库由一系列的二进制动态库共同构成,通常使用C/C++进行开发,这些库能被Android系统中不同的组件使用,它们通过Android应用程序框架为开发者提供服务。与框架层的系统服务相比,核心类库不能够独立运行于线程中,而需要被系统服务加载到其进程空间里,通过类库提供的JNI接口进行调用。
核心类库的来源主要有两种,一种是系统原生类库,Android为了提高框架层的执行效率,使用C/C++来实现它的一些性能关键模块,如:资源文件管理模块、基础算法库,等等。而另一种则是第三方类库,大部分都是对优秀开源项目的移植,它们是Android能够提供丰富功能的重要保障,如:Android的多媒体处理,依赖于开源项目OpenCORE的支持;浏览器控件的核心实现,是从Webkit移植而来;而数据库功能,则是得益于Sqlite。Android会为所有移植而来第三方类库封装一层JNI接口,以供框架层调用。
为了帮助游戏和图形图像处理等领域的开发者搭建更高效的应用,Android将数学函数库、OpenGL库等核心类库以NDK的形式提供给开发者,开发者可以基于NDK更高效地构建算法,进行图形图像绘制。从实践的角度看,只要能获取到底层类库的头文件信息,开发者就可以逾越NDK的界限,用其他核心类库的接口进行开发。但这样做的危险之处在于兼容性差,Android在版本变迁时,可能会替换或修改一些类库接口或实现,这就会导致依赖于这些类库的应用无法运行。而NDK提供的都是稳定的类库实现,不会再做修改,以保证使用NDK的应用具有向上的兼容性。
一下是一些核心库:
*系统 C 库 - 一个从 BSD 继承来的标准 C 系统函数库( libc ), 它是专门为基于 embedded linux 的设备定制的。
* 媒体库 - 基于 PacketVideo OpenCORE;该库支持多种常用的音频、视频格式回放和录制,同时支持静态图像文件。编码格式包括MPEG4, H.264, MP3, AAC, AMR, JPG, PNG 。
* Surface Manager - 对显示子系统的管理,并且为多个应用程序提 供了2D和3D图层的无缝融合。
* WebKit:网络浏览器的核心
* SGL - 底层的2D图形引擎
* 3D libraries - 基于OpenGL ES 1.0 APIs实现;该库可以使用硬件 3D加速(如果可用)或者使用高度优化的3D软加速。
* FreeType -位图(bitmap)和矢量(vector)字体显示。
* SQLite - 一个对于所有应用程序可用,功能强劲的轻型关系型数据库引擎。
2、Android 运行库
和所有的Java程序运行平台一样,为了实现Java程序在运行阶段的二次编译, Android为它们提供了运行时(Runtime)的支撑。
Android的运行时由Java核心类库和Java虚拟机Dalvik共同构成。Java核心类库涵盖了Android框架层和应用层所要用到的基础Java库,包括Java对象库、文件管理库、网络通信库,等等。
Dalvik是为Android量身打造的Java虚拟机,负责动态解析执行应用、分配空间、管理对象生命周期等工作。如果说框架层是整个Android的大脑,决定了Android应用的设计特征,那么,Dalvik就是Android的心脏,为Android的应用提供动力,决定它们的执行效率。与为低端移动设备而设计的J2ME虚拟机不同,Dalvik是专门为高端设备而优化设计的。它没有采用基于栈的虚拟机架构,而是采取了基于寄存器的虚拟机架构设计。通常来说,基于栈的虚拟机对硬件的依赖程度小、生成的应用更节约空间,可以适配更多的低端设备;而基于寄存器的虚拟机,对硬件的门槛会更高一些,编译出的应用可能会耗费稍多的存储空间,但它的执行效率更高,更能够发挥高端硬件(主要指处理器)的能力。
Dalvik没有沿用传统的Java二进制码(JavaBytecode)作为其一次编译的中间文件,而是应用了新的二进制码格式文件.dex。在Android应用的编译过程中,它会先生成若干个.class文件,然后统一转换成一个.dex文件。在转换过程中,Android会对部分.class文件中的指令做转义,使用Dalvik特有的指令集OpCodes来替换,以提高执行效率。同时,.dex会整合多个.class文件中的重复信息,并对冗余部分做全局的优化和调整,合并重复的常量定义,以节约常量池耗费的空间。这使得最终得到的.dex文件通常会比将.class文件压缩打包得出的.jar文件更精简。
为了提升Android应用的执行效率,从垃圾回收器(Garbage Collection,GC)到编译器,Dalvik一直在各个方面进行优化。经常可以听到这样的消息:“新版本的Android系统,比上一个版本的效率高了x倍。”这大都是改善Dalvik的效果。在Android 2.2中,Dalvik引入了对JIT(Just-in-time)编译的支持,将上层应用的执行效率提升了2~4倍,开启了Android发展的新篇章。
每一个Android应用程序都在它自己的进程(Linux的一个Process)中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik被设计成一个设备可以同时高效地运行多个虚拟系统,Dalvik虚拟机依赖于linux内核的一些功能,比如线程机制和底层内存管理机制。
四、应用程序框架层
框架层是Android系统中最核心的部分,它集中体现了Android系统的设计思想。在Android之前,有很多基于Linux内核打造的移动平台。作为超越前辈的成功范例,框架层的设计正是Android脱颖而出的关键所在。从系统设计的角度来看,Android期望框架层是所有应用运行的核心,参与到应用层的每一次操作中,并进行全局统筹。Android应用的最大特征是基于组件的设计方式。每个应用都由若干个组件构成,组件和组件之间并不会建立通信信道,而是通过框架层的系统服务,集中地调度和传递消息。这样的设计方式相当于增加了一个中间层,该层了解所有组件的状况,可以更智能地进行协调,从而提升了整个系统的灵活性。框架层由多个系统服务(System Service)共同组成,包括组件管理服务、窗口管理服务、地理信息服务、电源管理服务、通话管理服务,等等。所有服务都寄宿在系统核心进程(System Core Process)中,在运行时,每个服务都占据一个独立的线程,彼此通过进程间的通信机制(Inter-Process Communication,IPC)发送消息和传输数据。应用层中的应用,时刻都在与这些系统服务打交道。每一次构造窗口、处理用户交互事件、绘制界面、获得当前地理信息、了解设备信息等操作,都是在各个系统服务的支持下实现的。
而对于开发者而言,框架层最直观的体现就是SDK,它通过一系列的Java功能模块,来实现应用所需的功能。SDK的设计决定了上层应用的开发模式、开发效率及能够实现的功能范畴。因此,对于开发者而言,关注SDK的变迁是一件很有必要的事情,SDK每个新版本的诞生,都意味着一些老的接口会被调整或抛弃,另一些新的接口和功能火热出炉。开发者不但要查看和关注那些被修改的接口,来检查应用的兼容性,并采取相应的策略去适应这些变化,更重要的是,开发者还要追踪新提供的接口,寻找改进应用的机会,甚至是寻求开发新应用的可能。
Android的应用程序框架为应用程序层的开发者提供APIs,它实际上是一个应用程序的框架。
五、应用程序层
Android应用层由运行在Android设备上的所有应用共同构成,它不仅包括通话、短信、联系人等系统应用(随Android系统一起预装在移动设备上),还包括其他后续安装到设备中的第三方应用。
第三方应用都是基于Android提供的SDK(Software Development Kit)进行开发的,并受到SDK接口的约束。而预装在设备中的系统应用,则可以调用整个框架层的接口和模块,其中的很多接口在SDK中是隐藏的,因此,系统应用具有比第三方应用更多的权利。
Android的应用都是基于Java语言来开发的,但在很多应用(尤其是游戏)中,需要进行大规模的运算和图形处理,以及使用开源C/C++类库。通过Java来实现,可能会有执行效率过低和移植成本过高等问题。因此在Android开发中,开发者可以使用C/C++来实现底层模块,并添加JNI(Java Native Interface)接口与上层Java实现进行交互,然后利用Android提供的交叉编译工具生成类库并添加到应用中。
为了让应用开发者能够绕过框架层,直接使用Android系统的特定类库,Android还提供了NDK(Native Development Kit),它由C/C++的一些接口构成,开发者可以通过它更高效地调用特定的系统功能。
但在Android上,开发者通常只能使用C/C++编写功能类库,而不是整个应用。这是因为,诸如界面绘制、进程调度等核心机制是部署在框架层并通过Java来实现的,应用只有按照它们规定的模式去编写特定的Java模块和配置信息,才能够被识别、加载和执行。
从Android 2.3(API 9)开始,新增了android.app.NativeActivity类,它是通过调用预定义的JNI接口来实现的。开发者可以基于NDK,通过C/C++语言来实现具体功能。这就意味着,开发者仅通过C/C++语言就能实现整个应用。这对于游戏开发者而言是一大喜讯,但由于控件在Android中并没有Native的实现,普通的应用开发者通常还是需要通过Java来实现上层界面。