第1章 准备工作
本章主要内容
❑ 您认识Android吗?
❑ 开发者能基于Android做些什么?
❑ 如何才能更好地利用Android这个开源项目?
❑ 如何搭建Android源码开发环境?
自2007年11月发布以来,Android已经经历了数个版本的更新,市面上采用该系统的移动设置数量也在飞速增长,目前,它已经是一个强大而成熟的系统,但是Google并没有停止,也没有减慢研发速度,而是在更加努力地将它做得更好、更完美!让我们带着前面的问题重新审视Android,一起迎接移动互联网的未来。
1.1 深入认识Android
首先,我们有必要对Android进行深入的认识。如果你或多或少对Android有一些了解,我仍然建议大家仔细地阅读本章的内容,因为你能从不同的侧面和深度重新认识 Android,这些内容是开发者必须了解的。如果你之前对Android没有任何了解,也不必担心,我们将仔细地为你讲解Android的每一个知识点。
这一节我们将为大家解答本章开头列出的部分问题,首先,将分析Android的众多技术亮点,让你对Android的概念以及它的功能有一个全面的了解;其次,分析Android的系统构架、剖析Android的初始化流程以及各个层次之间的关系,让你能够看到Android更真实的一面;最后,介绍了Android系统开发和应用开发相关的基础概念。
内容为大家准备得够丰富吧!是不是有些迫不及待了,让我们一起开始吧。
1.1.1 Android的系统构架
要深入学习Android,首先需要学习Android的系统构架。Android的系统构架和其操作系统一样,采用了分层的构架,层次非常清晰,因此要掌握它的构架并不难。前言中的图 1 为Android 的系统构架图,如果你对该图已经不陌生,并且理解图中所示的构架,那么你可以跳过这部分内容(或者快速浏览);如果你是第一次见到该图,建议你详细阅读该部分内容,因为整本书的内容都是以这幅图为基础的。我们会对图中的每一个模块进行详细地分析,让你真正掌握Android的技术内幕。
从前言中的图 1 可以看出,Android 分为五层,从高层到低层分别是应用程序层(Applications)、应用程序框架层(Application Framework)、系统运行库层(Libraries和Android Runtime)和Linux内核层(Linux Kernel)。下面分别来看各个层次为我们提供了什么功能,以及如何来运用这些功能。
1.应用程序层
Android会与核心应用程序包一起发布,该应用程序包包括图1为大家展示的主屏(Home)、E-mail客户端、SMS/MMS短消息程序、日历、地图、浏览器、联系人管理程序等。所有的应用程序都是使用Java语言编写的,通过调用应用程序框架层(Application Framework)所提供的API来完成。当然,你也可以使用Java通过JNI的方式,配合Android NDK来开发原生的应用程序,这样可以提高应用程序的效率,但是难度也大大增加——你需要精通C和C++等语言,并且对Android NDK所提供的为数不多的功能有很深的认识。因为Android NDK提供的功能不是太多,为了避免你做了很久之后才发现——原来 NDK 不支持某项功能,大家可以根据自己的需求来选择是否采用NDK开发原生程序。
2.应用程序框架层
应用程序框架层为开发人员提供了可以完全访问核心应用程序所使用的 API 框架。该应用程序的构架设计简化了组件的重用,任何一个应用程序(以及任何其他应用程序)都可以发布自己的功能模块(在遵循框架的安全性限制的前提下)。同样,该应用程序重用机制也使用户可以方便地替换程序组件。下面来看一下该层的每一个模块为我们提供的组件,如表1-1所示。
表1-1 应用程序框架层提供的组件及其功能描述
3.系统运行库层
系统运行库层包括程序库和Android运行库两部分,下面分别来介绍这两个部分。
(1)程序库
Android 包含一些C/C++库,这些库能被Android系统中的不同组件使用,它们通过应用程序框架为开发者提供服务,表1-2给出了这些核心库的功能介绍。
表1-2 系统运行库层包含的核心库及其功能描述
(2)Android 运行时库
从图 1 可以看出,Android 运行时库又分为核心库和Dalvik虚拟机两部分。核心库提供了Java语言核心库的大多数功能,这里主要通过JNI的方式向应用程序框架层提供调用底层程序库的接口。Dalvik虚拟机是为了能同时高效地运行多个VMs而实现的。Dalvik虚拟机执行.dex的Dalvik可执行文件,该格式的文件针对最小内存使用做了优化。Dalvik虚拟机是基于寄存器的,所有的类都经由Java汇编器编译,然后通过SDK中的dx工具转化成.dex格式并由虚拟机执行。Dalvik虚拟机依赖Linux的一些功能,比如线程机制和底层的内存管理机制。每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例。关于这部分内容,先简单向大家介绍到这里,后面会给大家详细分析Android SDK工具包和Dalvik虚拟机。
4.Linux内核层
Android依赖于Linux 2.6版内核提供的核心系统服务,例如安全、内存管理、进程管理、网络栈、驱动模块等。内核作为一个抽象层,存在于软件栈层和硬件层之间,Android 对内核进行了增强,主要表现在以下几个方面:
❑ 硬件时钟 (Alarm)
❑ 内存分配与共享 (Ashmem)
❑ 低内存管理器 (Low Memory Killer)
❑ Kernel调试 (Kernel Debugger)
❑ 日志设备 (Logger)
❑ Android IPC机制 (Binder)
❑ 电源管理 (Power Management)
到这里,我们对Android系统构架的分析就告一段落了,你现在至少应该明白整个Android系统的构架和每个模块的功能,以便为后面的深入学习打下基础。Android系统是如何启动的?启动过程中需要初始化什么内容?如果你不知道(或不完全知道)这些问题的答案,不必担心,下一小节将剖析Android系统启动时的初始化操作。
1.1.2 Android的初始化流程
上一小节分析了Android的系统构架,让大家对Android系统有了一个深入的认识;但是, Android 系统本身非常庞大,在深入分析每个模块的具体功能之前,有必要对其启动过程进行分析。我们需要了解这么一个庞大的系统在启动的时候需要执行哪些初始化操作。
Android系统在启动时首先会启动Linux基础系统,然后引导加载Linux Kernel并启动初始化进程(Init),如图1-1所示。
图1-1 启动Init进程
接着,启动Linux守护进程(daemons)。这个过程主要需要启动以下内容,如图1-2所示。
图1-2 启动Linux守护进程
❑ 启动USB守护进程(usbd)来管理USB连接。
❑ 启动Android Debug Bridge守护进程(adbd)来管理ADB连接。
❑ 启动Debug守护进程(debuggerd)来管理调试进程的请求(包括内存转换等)。
❑ 启动无线接口守护进程(rild)来管理无线通信。
在启动Linux守护进程的同时还需要启动Zygote进程,如图1-3所示。它主要包括以下需要启动和注册的内容:
图1-3 启动Zygote进程
❑ 初始化一个Dalvik虚拟机实例。
❑ 装载Socket请求所需的类和监听。
❑ 创建虚拟机实例来管理应用程序的进程。
再接着,需要初始化runtime进程,初始化过程如图1-4所示。在这个过程中需要处理以下操作:
图1-4 初始化runtime进程
❑ 初始化服务管理器。
❑ 注册服务管理器,以它作为默认Binder服务的Context管理器。
runtime进程初始化之后,runtime进程将发送一个请求到Zygote,开始启动系统服务,这时Zygote将为系统服务进程建立一个虚拟机实例,并启动系统服务,如图1-5所示。
图1-5 启动系统服务
紧接着,系统服务将启动原生系统服务,主要包括Surface Flinger和Audio Flinger。这些本地系统服务将注册到服务管理器(Service Manager)作为IPC服务的目标,如图1-6所示。
图1-6 启动本地服务并注册
系统服务将启动 Android 管理服务,Android 管理服务将都被注册到服务管理器上,如图1-7所示。
图1-7 启动并注册Android服务
最后,当系统加载完所有的服务之后会处于等待状态,等待程序运行。但是,每一个应用程序都将启动一个单独的进程。如图1-8所示,系统启动了一个Home进程和一个Contacts进程。那么,各个进程之间如何进行交互呢?这就需要使用IPC机制了,后面会详细介绍。
图1-8 在Android启动之后运行Home和Contacts进程
到这里,系统的整个启动过程就结束了,可以在上面运行应用程序了。你也应该对Android系统启动过程的每一步都有了深入的理解。实际上,这个启动过程就是从Android系统构架图中最底层的Linux内核层一步一步加载和注册到应用程序框架层,最终在应用程序层运行我们自己的应用程序。那么,各个层次之间又有什么样的关系呢?应用程序在最上层又是如何调用到最底层的核心服务的呢?下一小节将为大家分析各个层次之间的关系。
1.1.3 各个层次之间的相互关系
上一小节介绍了Android系统的启动过程,本小节将介绍Android应用程序是如何按照层次关系来调用最底层的硬件和服务的。如果你对上一节的内容理解得还不够深入,那么可以回去再仔细地看一遍,这样才能更好地理解本小节的内容。好的,相信你已经准备好了,开始吧。
在Android中运行的应用程序都是通过以下三种方式来层层深入的:
❑ App→Runtime Service→Lib
❑ App→Runtime Service→Native Service→Lib
❑ App→Runtime Service→Native Daemon→Lib
下面就分别来分析这三种方式,我们还是采用流程图的方式来为大家展示。
App→Runtime Service→Lib方式对应的流程图如图1-9所示。
图1-9 App→Runtime Service→Lib方式的流程图
通过图1-9我们可以看出,在Android平台上,应用程序首先是在应用程序层通过Binder IPC调用应用程序框架层的Runtime Service,然后再通过JNI与运行库中的原生服务绑定,并动态地加载Hal库,进而调用Linux内核层的Kernel Driver。为了便于大家更好地理解,我们通过一个实例(Location Manager)来为分析该流程,如图1-10所示。
图1-10 Location Manager调用流程
以上就是第一种方式的调用过程,接下来我们再看一下第二种方式(App→Runtime Service→Native Service→Lib)是如何调用的。这种方式通常被Android原生服务所采用,同样先看一下调用流程图,如图1-11所示。
图1-11 App→Runtime Service→Native Service→Lib方式的流程
图1-11为我们展示了Android原生服务的调用流程,可以看出,与第一种方式相比,只多了一个通过IPC机制调用原生服务并进行动态装载的过程。所以,这里我们就不再重复介绍,但还是给出一个Audio的例子,如图1-12所示。
图1-12 Audio原生服务的调用流程
从图1-12可以看出,应用程序调用了应用程序框架层的MediaPlayer,然后调用系统运行库层的MediaPlaye。这时MediaPlaye又分别调用了Media Framework和AudioFlinger,而后通过AudioFlinger调用指定的库(libaudio.so),最后才调用到Kernel Driver。
下面来看一下最后一种方式“App→Runtime Service→Native Daemon→Lib”,如图1-13所示。这种方式通常用于守护进程的连接。
图1-13 原生守护进程的调用流程
从图1-13可以看出,这种方式比原生服务的调用更简单,它直接通过JNI绑定原生服务,再通过sockets调用守护进程进行动态加载。下面就来看一个简单的例子,电话管理(Telephony Manager)的调用就是这样一个原生的守护进程调用,其流程如图1-14所示。
图1-14 Telephony Manager的调用流程
这个调用的过程非常简单,相信图1-14已经表述得足够清楚了。
1.1.4 Android系统开发(移植)和应用开发
通过前面的学习,我们了解到 Android 是一个庞大且完善的系统,我们可以基于 Android来进行哪些开发工作?每一种开发工作又有什么不同?不同的开发工作需要掌握的技术有什么差异?学完本小节的内容你就会知道应该如何利用Android来开发自己所需要的产品。
因为Android是一个开源的操作系统,所以可以选择的开发方式主要有以下两种:
❑ Android系统开发(移植)
❑ Android应用开发
1.Android系统开发(移植)
Android 系统开发(移植)属于底层的开发工作,主要针对 Android 系统本身进行完善和将其移植到其他的硬件平台,因此需要掌握Android系统构架中的Linux内核层和系统运行库层,如图1-15所示。
图1-15 Android系统开发(移植)结构
Android系统开发主要涉及Libraries和Android Runtime这两部分内容,一般就是在本地编写C/C++代码,然后通过JNI向上层提供调用接口,主要是为应用开发提供服务等工作。
Android系统移植则主要涉及硬件抽象层和Linux 内核层,移植的主要工作是将驱动移植到不同的硬件上,使其能完美地运行 Android 系统。这些驱动又主要包括设备驱动和 Android专用驱动。
无论是系统开发还是系统移植,都是由底层直接操作Android的源代码,因此在开发之前,我们首先就需要准备Android的源码。下一节将向大家详细介绍如何获取和编译Andorid的源码,以及Android源码的结构。
2.Android应用开发
Android应用开发主要是根据Android系统所提供的API来完成各种应用程序的编写,所使用的API属于Android的应用框架层,如图1-16所示。如果Android系统没有提供某些API,那么只能通过在Android系统底层编写C/C++代码来开发这些API并向Android应用框架层提供接口。但是笔者不建议这样做,因为这很可能会导致你的应用程序与其他 Android 系统不兼容。
图1-16 Android应用开发框架
我们自己所开发出来的应用程序与应用层的应用程序运行在同一个层次上,因此再次提醒大家,开发应用时一定要遵循Android API框架的规定,以避免开发的应用程序不兼容。
另外,应用开发属于上层开发,不需要接触底层的 C/C++代码,所以,开发前我们只需要准备Android SDK和模拟器即可(当然,你可能也需要使用一款IDE,推荐使用Eclipse)。最后,Android SDK既可以通过编译源码获得,也可以在Android的官方网站下载编译好的SDK。下面将讲解如何通过编译源码的方式来取得Android SDK,以及SDK的结构和开发工具包。