一、Android 的系统架构
1、应用层
Android 平台的应用层上包括:各类与用户直接交互的应用程序,或由 Java 编写的运行于后台的服务程序(即:第三方应用、系统应用)。
其中,系统应用既可作为用户的应用直接使用,也可以提供开发者从自己开发的第三方应用中访问的功能(如:开发的第三方应用需要发送短信,开发者无需自己构建该功能,可以调用已安装的短信系统应用来发送。)
2、Framework 层
该层是用 Java 来实现的,它提供开发 Android 应用程序所需的一系列基础 API 支持,包括了开发所需要的一系列组件和系统服务等。
(1)应用程序框架层
该层可理解为 Android SDK,提供四大组件、视图系统(View System)、以及各种 Manager 等开发中所用到的基础部件,如下:
应用程序框架层 类库名称 | 功能 |
活动管理器(ActivityManager) | 管理各个应用程序生命周期,并提供常用的导航回退功能,为所有程序的窗口提供交互的接口 |
窗口管理器(WindowManager) | 对所有开启的窗口程序进行管理 |
内容提供者(ContentProvider) | 提供一个应用程序访问另一个应用程序数据的功能,实现应用程序之间的数据共享 |
视图系统(ViewSystem) | 创建应用程序的基本组件,包括:列表(lists)、网格(grids)、文本框(text boxes)、按钮(buttons)等 |
通知管理器(NotificationManager) | 使应用程序可以在状态栏中显示自定义的客户提示信息 |
包管理器(PackageManager) | 对应用程序进行管理,包括:安装应用程序、卸载应用程序、查询相关权限信息等 |
资源管理器(ResourceManager) | 提供各种非代码的资源,供应用程序使用,包括:本地化字符串、图片、音频等 |
位置管理器(LocationManager) | 提供位置服务 |
电话管理器(TelephonyManager) | 管理所有的移动设备功能 |
(2)Java 系统服务层
该层的系统服务又可以分为两种:Java 核心系统服务、Java 硬件系统服务。
<1> Java 核心系统服务是 Android 系统正常运转的基础,包括:AMS、WMS、PMS 等。
核心平台服务 | 功能 |
ActivityManagerService | 管理所有 Activity 的生命周期与堆栈(Stack) |
WindowManagerService | 位于 SurfaceFlinger 之上,将要绘制到机器画面上的内容传递给 SurfaceFlinger |
PackageManagerService | 加载 Apk 文件的信息,提供信息显示系统中设置了哪些包,以及加载了哪些包 |
<2> Java 硬件服务是为应用提供硬件控制服务,包括:电话服务、wifi 服务、PowerManagerService 等。
硬件服务 | 功能 |
AlarmManagerService | 在特定时间后运行指定的应用程序(像定时器) |
ConnectivityService | 提供有关网络当前状态的信息 |
LocationService | 提供终端当前的位置信息 |
PowerService | 设备电源管理服务 |
SensorService | 提供 Android 中各种传感器(如:磁力感应器、加速度传感器)的感应值 |
TelephonyService | 提供话机状态和电话服务 |
WifiService | 控制无线网络连接(如:AP搜索、连接列表管理等) |
这两层之间通过 Binder 实现进程间通信,允许 Framework 跨进程来调用 Android 的系统服务代码,这使得框架 API 与 Android 系统服务之间能够进行交互。
( 总结:应用程序 ----SDK----> 系统框架层 ----Binder IPC----> 系统服务层 )
示例:当某个App获取GPS信息时
3、Native 层
该层是用 C/C++ 来实现的,包括:C/C++ libs、Android RunTime、HAL。
(1)C/C++ libs(C/C++ 编写的系统类库):
<1> 本地守护进程
init 进程,根据 init.rc 文件中的定义,启动本地守护进程。这些进程会常驻在系统中,有的只会启动一次,有的若退出了,还会被 init 进程启动。其具体的启动方式是在 init.rc 文件中定义的。常见的守护进程如下:
守护进程 | 功能 |
vold | 管理存储设备,自动安装存储设备,将设备分区格式化 |
netd | 管理蓝牙、wifi、usb 等各种网络连接 |
installd | 负责安装及卸载软件包,确认软件包的完整性 |
adbd | 提供可以调试 Android 的环境 |
service manager | Binder 通信的大管家 |
surface flinger | 负责 Android 系统的 UI 图形显示 |
media server | 负责播放音频、视频、camera 拍照录像等 |
<2> Native 系统服务
由 C++ 编写,运行在本地守护进程中,比如:media server 守护进程中,就包含了:AudioFlinger、MediaPlayerService、CameraService、AudioPolicyService、SoundTriggerHwService 等服务。
在所属进程初始化时,会将 Native 系统服务注册到 ServiceManager 中,这样其它的应用或服务就可以通过 Binder 机制调用 Native 系统服务了。(注:也可以自己开发一个 Native 系统服务,实现其 Binder 接口,这样 Native 层的其它应用或服务就可以调用该服务了。若我们开发的 Native 系统服务需要提供给 Java 层应用使用,就需要实现一个 Java 接口,然后通过 JNI 调用 Native 系统服务。)
<3> 功能性的 Native 类库支持
比如:Webkit、OpenGL ES、SQLite 等。
整个系统服务结构,如下图所示:
(2)Android RunTime(Android 运行环境,对 Java 提供支持):
<1> 虚拟机(Dalvik、ART)
作用:面向 Linux,是为嵌入式操作系统设计的虚拟机,主要负责完成对象生命周期管理、堆栈管理、线程管理、安全和异常管理、以及垃圾回收等。
Android 为每个程序提供一个虚拟机(VM),可以使每个 App 都运行在独立的运行环境中,使稳定性提高,并且一个 VM 能运行多个进程。Android 的 Apk 都被编译成字节码,在运行时,VM 先将字节码编译成真正可执行的代码,否则不同硬件设备的兼容是很大的麻烦。
<2> 核心库(core libs):提供了 Java SE API 的多数功能,包括:JNI,并提供 Android 的核心 API,如:android.os、android.net、android.media 等。
(3)硬件抽象层(HAL)
若能将 Android 的应用框架层与 Linux 系统内核的设备驱动隔离,使应用程序框架的开发尽量独立于具体的驱动程序,则 Android 将减少对 Linux 内核的依赖。
HAL 由此而生,基于商业隐私考虑,许多硬件设备厂商不希望公开其设备驱动的源代码,对 Kernel 层进行二次封装,屏蔽数据处理细节,运行于用户空间。它是对 Linux 内核驱动程序进行的封装,将硬件抽象化,屏蔽掉了底层的实现细节。HAL 规定了一套应用层对硬件层读写和配置的统一接口,本质上就是将硬件的驱动分为:用户空间、内核空间(Linux 内核驱动程序运行于内核空间,HAL 运行于用户空间)。
[说明]
<1> JNI(Java Native Interface):Java 本地接口,使得 Java 与本地其它类型的语言(如:C、C++)可以进行交互。(注:JNI 是属于 Java 的,与 Android 无直接关系)
<2> NDK(Native Development Kit):是 Android 的一个开发工具包,用于快速开发 C、C++ 的动态库,并自动将 SO 和应用一起打包成 Apk,即:可通过 NDK 在 Android 中使用 JNI 与本地代码进行交互。(注:NDK 是属于 Android 的,与 Java 无直接关系)
NDK 可以通过 Native Code 跨过 dalvik runtime,直接调用到 Android 内核资源,而 SDK 需要在 dalvik runtime 环境下,才能调用到内核资源。Android 提供了 JNI 使两者可以进行相互调用和通信。
4、Kernel 层
Android 以 Linux 操作系统内核为基础,借助 Linux 内核服务,实现硬件设备驱动、进程和内存管理、网络协议栈、电源管理、无线通线等核心功能。
Android 内核对 Linux 内核进行了增强,增加了一些面向移动计算的特有功能,例如:低内存管理器(LMK,Low Memory Keller)、匿名共享内存(Ashmem)、轻量级的进程间通信 Binder 机制等。这些内核的增强,使 Android 在继承 Linux 内核安全机制的同时,进一步提升了内存管理、进程间通信等方面的安全性。Android 内核的主要驱动模块如下:
驱动名称 | 说明 |
Android 电源管理(Power Manager) | 针对嵌入式设备的,基于标准 Linux 电源管理系统的,轻量级的电源管理驱动 |
低内存管理器(Low Memory Keller) | 可以根据需要杀死的进程,来释放需要的内存。扩展了 Linux 的 OOM 机制,形成独特的 LMK 机制 |
匿名共享内存(Ashmem) | 为进程之间提供共享内存资源,同时为内核提供回收和管理内存的机制 |
日志(Android Logger) | 一个轻量级的日志设备 |
定时器(Android Alarm) | 提供了一个定时器用于把设备从睡眠状态唤醒 |
物理内存映射管理(Android PMEM) | DSP 及其它设备,只能工作在连续的物理内存上,PMEM 用于向用户空间提供连续的物理内存区域映射 |
Android 定时设备(Android Timed device) | 可以执行对设备的定时控制功能 |
Yaffs2 文件系统 | Android 采用大容量的 NAND 闪存作为存储设备,使用 Yaffs2 作为文件系统管理大容量 MTD NAND Flash,Yaffs2 占用内存小,垃圾回收简捷 |
Android Paranoid 网络 | 对 Linux 内核的网络代码进行了改动,增加了网络认证机制。可在IPV4、IPV6、蓝牙中设置,由 ANDROID_PARANOID_NETWORK 宏来启用此特性 |
二、Android 的系统源码
一个 Android 项目包括了许多模块,所有项目模块通过 repo 中的 manifest.xml 统一管理,repo init 时,会拉下来一个 .repo 文件,里面就有这个 manifest.xml 文件。然后 repo sync 的工程内容就是这个 manifest.xml 仓库中所对应的模块。
说明:(1)共线:指的是芯片相关平台基线;(2)共分支:指的是模块各自的版本控制。
1、源码的核心模块
(1)build/soong、build/make:主要跟编译规则相关,大部分都是一些 mk 配置,来决定系统按照什么顺序来串联和编译,这部分适配好后,就可以 lunch 了。
(说明:makeFile 文件是一份定义了源文件间依赖关系、如何编译各个源文件,并生成可执行文件的说明书,决定了整个工程的编译规则,实现自动化编译。[ 注意:Android P 版本开始陆续使用 .dp 取代 .mk ] )
(2)system/core/:该目录下包括不少系统核心工具,这部分可以单独编译 boot.image。
(3)frameworks/base/:这里是系统 framework 部分,包括:java 和 native,编译后会生成两个核心文件:framework.jar 和 services.jar。
(4)art/:这里是虚拟机的内容。
(5)packages/apps:这里是系统 app 的内容。
(6)out/target/product/:编译生成的文件都存在该目录下。
三、Android 系统的启动流程
Android 系统启动过程,由上图(从下往上)的一个过程:Loader ——> Kernel ——> Native ——> Framework ——> App。
1、Loader 层 (激活 Kernel)
(1)启动电源以及系统启动:当电源按下时,引导芯片代码将固化在 ROM 中的引导程序 Bootloader 加载到 RAM 中,然后执行。
(2)引导程序 Bootloader:它是 Android 操作系统开始运行前的一个小程序,负责把系统 OS 拉起来并运行。
(3)Linux 内核启动:内核启动时,设置缓存、被保护存储器、计划列表、加载驱动等,为最终调用系统内核准备好环境。
2、Kernel 层 (Android 的内核空间,到这里才刚刚进入 Android 系统)
Bootloader 启动 Kernel 的 swapper 进程(pid=0),它是内核的首个进程,用于初始化进程管理、内存管理、加载各种驱动。
更重要的是启动如下两个重要进程:
(1)init 进程(pid=1):用户进程的鼻祖。
(2)kthreadd 进程(pid=2):内核进程的鼻祖。
3、Native 层 (进入用户空间)
(1)本层中,init 进程是大主管,它负责孵化各种系统级服务、守护进程等。更重要的是孵化出 Zygote 进程:Java 进程的鼻祖。
init 进程的作用:
<1> 解析两个配置文件:系统配置文件(init.rc)、平台相关的配置文件。
解析函数入口为:int parse_config_file(const char *fn);
<2> 创建 zygote(注:其本身是一个 native 的应用程序),并由此开始分三步,开创了 Java 世界:
[1] 调用 JNI 的虚拟机,创建函数;
[2] 提前注册一些 JNI 函数,供后续 Java 层使用;
[3] 开始走进 Java 层,及最终调用到 zygoteinit 的 main() 函数。
a、建立 IPC 通信的服务端 ----> registerzygotesocket();
b、预加载类和资源;
c、启动 system_server 进程,该进程是 framework 的核心,系统 service 的驻留进程;
d、待 zygote 从 startsystemservice 返回后,开始等待请求:runselectloopmode(),并由 runonce() 进行处理;
<3> 管理属性服务。
(2)Media Server 进程:负责启动和管理整个 C++ Framework,包含:AudioFlinger、Camera Service 等服务。
4、Framework 层 (在 Native 之上,也是用户空间,主要给 App 层提供 API 以及系统服务)
(1)本层中,Zygote 进程是大主管,它负责注册 Zygote Socket 服务端套接字、加载虚拟机、preloadClasses、preloadResources。
(2)System Server 进程:负责启动和管理整个 Java Framework,包含:AMS、PMS 等服务。
(代码路径:frameworks/base/services/java/com/android/server/SystemServer.java)
5、APP 层 (应用程序)
所有 App 进程,都是由 Zygote 进程 fork 生成的。
总结:程序代码是死的,系统运转是活的,要以动态视角去理解系统架构。通过系统调用(SysCall)连通内核与用户空间,通过 JNI 打通用户空间的 Java 层和 Native 层,通过 Binder、Socket、Handler 等,进行跨进程、跨线程的信息交换。