Android 操作系统架构开篇:
http://gityuan.com/android/
https://cloud.tencent.com/developer/article/1429122
Android架构图(五层框架):https://www.cnblogs.com/pengdonglin137/p/3858254.html
官方系统架构图:https://developer.android.google.cn/guide/platform/
Android Studio官方介绍:https://developer.android.google.cn/studio/
Android Studio官方详解:https://developer.android.google.cn/studio/intro/
Android控件架构:https://cloud.tencent.com/developer/article/1337229
一、引言
虽然 Android 系统非常庞大且错综复杂,需要具备全面的技术栈,但整体架构设计清晰。Android 底层内核空间以 Linux Kernel 作为基石,上层用户空间由 Native系统库、虚拟机运行环境、框架层组成,通过系统调用(Syscall)连通系统的内核空间 与 用户空间。对于用户空间主要采用 C++ 和 Java 代码编写,通过 JNI 技术打通用户空间的 Java层 和 Native层(C++/C),从而连通整个系统。为了能让大家整体上大致了解Android系统涉及的知识层面,先来看一张Google官方提供的经典分层架构图:
查看:https://developer.android.com/guide/platform
从 下 往 上 依次分为:
- Linux 内核
- HAL ( 新的 Android 架构图细化特定分出一个:Hardware Abstraction Lay (HAL)层 )
- 系统Native库 和 Android运行时 环境
- Java框架层
- 应用层
这 5 层架构每一层都包含大量的子模块或子系统。
上图采用静态分层方式的架构划分,众所周知,程序代码是死的,系统运转是活的,各模块代码运行在不同的进程(线程)中,相互之间进行着各种错终复杂的信息传递与交互流,从这个角度来说此图并没能体现Android整个系统的内部架构、运行机理,以及各个模块之间是如何衔接与配合工作的。为了更深入地掌握Android整个架构思想以及各个模块在Android系统所处的地位与价值,计划以Android系统启动过程为主线,以进程的视角来诠释Android M系统全貌,全方位的深度剖析各个模块功能,争取各个击破。这样才能犹如庖丁解牛,解决、分析问题则能游刃有余。
其他框架图表示:
可以很明显看出,Android 系统架构由 4 部分组成,分别是:Linux Kernel、Android Runtime 和 Libraries、Application Framework、Applications。学过计算机网络都知道 OSI/RM,就会知道分层的好处就是使用下层提供的服务而为上层提供统一的服务,屏蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各司其职,各层提供固定的SAP(Service Access Point),专业点可以说是高内聚、低耦合。 如果你只是做应用开发,就不需要深入了解Linux Kernel层。
其他框架图表示:
其他框架图表示:
从Linux操作系统的角度来看,第2层是内核空间与用户空间的分界线,第1层运行于内核空间,第2、3、4层次运行于用户空间。
总结:
- 1. 应用层:应用是用java语言编写的运行在虚拟机上的程序,比如Email客户端,SMS短消息程序,日历等。
- 2. 应用框架层:这一层是编写Google发布的核心应用时所使用的API框架,开发人员同样可以使用这些框架来开发自己的应用,这样便简化了程序开发的结构设计,但是必须要遵守其框架的开发原则。
- 3. 系统运行库(C/C++库以及Android运行库)层:当使用Android应用框架时,Android系统会通过一些C/C++库来支持我们使用的各个组件,使其更好的为我们服务,比如其中的SQLite(关系数据库),Webkit(Web浏览器引擎)。
- 4. Linux内核层:Android的核心系统服务给予Linux2.6内核,如安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核,比如Binder IPC(Internet Process Connection进程间通信)驱动,android的一个特殊驱动程序,具有单独的设备节点,提供进程间通信的功能。
Android的系统架构不仅从宏观上认识了Android系统,同时,也给我们的学习与实践指明了方向。若是从事Android应用开发,那应该研究Android的应用框架层和应用程序层;若是从事Android系统开发,那应该研究Android的系统库和Android运行时;若是从事Android驱动开发,那应该研究Android的Linux内核
其他框架图表示:
从Android架构得出我们必须要掌握的知识点:
- Linux知识。Android是基于Linux内核的,编译Android源码也必须在Linux上,所以必须掌握Linux的基础知识(操作区别、简单指令、进程等),没事可以装个VM虚拟机玩玩。
- C/C++知识。Android大部分核心库是C/C++的动态链接库,系统大部分隐藏API都是在这里面的,而且你看哪条面试中没写要求熟悉NDK(Java+C/C++形式)开发,所以必须熟悉C/C++知识,C语言看谭浩强的《C语言程序设计》就可以,NDK推荐看《Android C++高级编程》。
- Java知识。Android是80%的Java package,IDE和语言都是Java,没理由不具备精通级的Java知识。尤其是多线程、I/O流、面向对象思想、http和socket网络等,面试必问题,Java的进阶书书大家都知道就不再提了。
- T-SQL知识(可以只是基础的增删改查和子查询)。
高级工程师要掌握的知识:
- 数据结构(基础)
- 设计模式(推荐看《大话设计模式》,然后再带入Android API看设计模式在Android中的应用)
- Web开发语言+Html+JS(推荐php和jsp,做到最后怎么着都得熟悉一门Web开发语言)
以上皆是知识点,以下是我认为可以有的一些点:
- GitHub(这简直就是摆在那里的财富,各种你需要的Android的例子上面都有,只是你必须要学会去搜索)
- Android ROM(想想自己做一个专属的ROM屌不屌)
- afinl、thinkandroid等各种Android开源快速开发框架(要是能参与开源项目就离大牛不远了)
- iOS开发(我是很羡慕人家用苹果机我用win7系统的)
- 各种Android开发论坛(学习最快的形式是交流和传授)
如觉得还有技术方面提升的地方再补充。
Android开发的三个层次
我觉得Android开发上有三个层次技术:
1. 第一个层次和传统的嵌入式Linux最接近,主要涉及的是CPU、GPU以及外设的驱动以及使能方面。多需要熟悉Linux内核,Android框架定义中驱动的接口规范等等,这部分开源社区的力量最大。这个层次技术主要需求方是是各种CPU和Android设备解决方案供应商。
2. 第二个层次主要是涉及Android框架中间件部分,如多媒体/3D框架,Java虚拟机等等,这部分Google控制的是最严格的,因为他要控制 Android各种feature以及捆绑自己的移动互联网应用,必须规范中间件。这部分所涉及的软件技术也最多,从各种C/C++库,Java虚拟机性能,用户体验抽象到数据库设计等等很大的内涵。开发的一般也是选择一个方向发力。另外深度定制Android ROM重点也是这个层次。
3. 第三个层次就是App开发层次,这个层次主要就是利用Android SDK开发了。很多C/C++出身的觉得是用Java开发,其实Java就是啥都是指针的C++,外带try/catch以及垃圾收集,上手其实是很快的。Android程序最重要一点是理解生命周期概念,将一个Activity和Linux进程关系搞清楚,啥时候这个进程启动,啥时候睡眠,啥时候退出,后台的事件循环如何运行的,最后时刻要提醒自己虚拟机在运行,垃圾收集在运行。Google Code上有还多参考代码,在看中学,体会很快的。
另外,本人采用了一种特别的模式来进行Android程序开发:Java只负责界面,用NDK来做各种复杂的业务和数据处理,Java与NDK之间设计好API以及事件传递方式(Android SDK 中Localsocket就可以很好用做事件发送)。这种方式适合C/C++背景的开发人员上手Android,Java无需达到熟练即可。
二、Android 架构
Google 提供的5层架构图很经典,但为了更进一步透视 Android 系统架构,本文更多的是以进程的视角,以分层的架构来诠释Android 系统的全貌,阐述 Android 内部的环环相扣的内在联系。
系统启动架构图
图解:Android 系统启动过程由上图从下往上的一个过程是由 Boot Loader 引导开机,然后依次进入 -> Kernel
-> Native
-> Framework
-> App
,接来下简要说说每个过程:
关于 Loader 层:
- Boot ROM:当手机处于关机状态时,长按 Power 键开机,引导芯片开始从固化在 ROM 里的预设代码开始执行,然后加载引导程序到 RAM;
- Boot Loader:这是启动 Android 系统之前的引导程序,主要是检查 RAM,初始化硬件参数等功能。
2.1 Linux内核层
Android 底层便是 Linux内核。例如 Android Runtime (ART 即 ART 虚拟机 ) 最终调用底层 Linux 内核来处理线程和底层内存管理等底层功能。使用 Linux 内核可让 Android 利用 Linux 内核的安全机制为 Android 提供相应的保障,也允许设备制造商为内核开发硬件驱动程序。
随着Android的完善,随着产品完善,很多时候,应用级App简单调用系统提供API已无法满足我们开发需求,那么这个时候,我们就不得不硬着头皮去深入底层,了解NDK,学习JNI等等一些高级编程技术了。
什么是 NDK ?
- 定义:Native Development Kit,是Android的一种开发工具包
- 作用:快速开发C、 C++的动态库,并自动将so和应用一起打包成 APK 即可通过 NDK在 Android中 使用 JNI与本地代码(如C、C++)交互
- 优点:运行效率高、代码安全性高、跨平台
什么是 JNI ?
- 定义:Java Native Interface,
- 作用:通过 JNI 能使 Java 调用 C++
进程加载流程:
- 启动 Kernel 的 swapper 进程(pid=0):该进程又称为 idle 进程, 系统初始化过程 Kernel 由无到有开创的第一个进程,用于初始化进程管理、内存管理,加载 Display、Camera Driver、Binder Driver 等相关工作;
- 启动 kthreadd 进程(pid=2):是 Linux 系统的内核进程,会创建内核工作线程 kworkder,软中断线程 ksoftirqd,thermal等内核守护进程。 kthreadd 进程是所有内核进程的鼻祖。
2.2 硬件抽象层 (HAL)
硬件抽象层 (HAL) 提供标准接口,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一组接口,比如WIFI/蓝牙模块,当框架API请求访问设备硬件时,Android系统将为该硬件加载相应的库模块。
2.3 Android Runtime & 核心库 和 Native 系统库
Android 应用程序是用 Java 语言开发编写的,程序在 Android运行环境 中执行,Android运行环境 分为 核心库(Core Labraries:安卓开发核心库) 和 Dalvik虚拟机(DaLvik Virtual Machine)两部分。
2.3.1 Android Runtime 安卓运行环境
- core Labraries (安卓开发核心库,即 核心库):Android 包含一个核心库的集合,核心库提供了Java语言API中的大多数功能,既兼容了大多数Java语言所需要调用的功能函数,同时也包含了 Android 的一些核心API,如 android.os、android.net、android.media 等等。
- Dalvik Virtual Machine ( Dalvik 虚拟机 ):是一种基于寄存器的 java 虚拟机,Dalvik 虚拟机主要是完成对生命周期的管理、堆栈的管理、线程的管理、安全和异常的管理以及垃圾回收等重要功能。Android 程序不同于J2ME(Java ME 又称为J2ME,即 Java Platform,Micro Edition)程序,每个Android应用程序都有一个专有的进程,并且不是多个程序运行在一个虚拟机中,而是每个Android程序都有一个Dalivik虚拟机的实例,并在该实例中执行。Dalvik虚拟机是一种基于寄存器的Java虚拟机,而不是传统的基于栈的虚拟机,并进行了内存资源使用的优化,以及支持多个虚拟机的特点。需要注意的是,不同于J2me,Android程序在虚拟机中执行的并非编译后的字节码,而是通过转换工具 dx 将 Java字节码转成 dex 格式的中间码。
Android 5.0 以下的版本 运行的是 Dalvik 虚拟机。
Android 5.0+ 运行的 ART 虚拟机(Android Runtime)
对于运行 Android 5.0(API 级别 21)或更高版本的设备,每个应用都在其自己的进程中运行,并且有其自己的 Android Runtime ( 即 ART 虚拟机 ) 实例。ART 编写为通过执行 DEX 文件在低内存设备上运行多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。
每一个 Android 应用程序都是 Dalvik 虚拟机中的实例,运行在他们自己的进程中。Dalvik虚拟机设计成,在一个设备可以高效地运行多个虚拟机。Dalvik虚拟机可执行文件格式是 .dex,dex 格式是专为 Dalvik 设计的一种压缩格式,适合内存和处理器速度有限的系统。
大多数虚拟机 包括 JVM 都是基于栈的,而 Dalvik 虚拟机 则是基于寄存器的。两种架构各有优劣,一般而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,可以将 Java .class 转换成 .dex 格式。一个dex文件通常会有多个 .class。由于 dex 有时必须进行最佳化,会使文件大小增加1-4倍,以 ODEX 结尾。
Dalvik 与 Java虚拟机 的区别:
- (1)Dalvik 基于寄存器,而 JVM 基于栈。
- (2)Dalvik虚拟机运行的是其专有的文件格式Dex,而Java虚拟机运行java字节码。
- (3)Dex文件格式可以减少整体文件尺寸,提高I/O操作的类查找速度。
- (4)每个APP对应一个独立的虚拟机实例,APP的每个线程对应一个Linux线程。
- (5)有一个特殊的虚拟机进程Zygote,其是虚拟机实例的孵化器。它在系统启动的时候就会产生,如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。
Dalvik 虚拟机 依赖于Linux 内核提供基本功能,如线程和底层内存管理。
每个应用都在其自己的进程中运行,都有自己的虚拟机实例。ART 通过执行DEX文件可在设备运行多个虚拟机,DEX文件是一种专为 Android 设计的字节码格式文件,经过优化,使用内存很少。ART主要功能包括:预先(AOT)和即时(JIT)编译,优化的垃圾回收(GC),以及调试相关的支持。
ART 的部分主要功能包括:
预先 (AOT) 和即时 (JIT) 编译
优化的垃圾回收 (GC)
更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段
在 Android 版本 5.0(API 级别 21)之前,Dalvik 是 Android Runtime。如果您的应用在 ART 上运行效果很好,那么它应该也可在 Dalvik 上运行,但反过来不一定。
Android 还包含一套核心运行时库,可提供 Java API 框架使用的 Java 编程语言大部分功能,包括一些 Java 8 语言功能。
2.3.2 Native 系统库(系统运行库,即 原生 C/C++ 库 )
这层中包含了支持整个系统正常运行的基础库,由于这些库多数都由C/C++实现,因此也被一些开发人员成为“C库层”,以区别于应用程序框架层。
许多 Android 核心的系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供的 Java 框架 API 用来向应用程序提供其中部分原生库的功能。例如,您可以通过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。
总的来说,就是 Android 包含一个 C/C++库 的 集合,供 Android 系统的各个组件使用。这些功能通过 Android 的应用程序框架(application framework)暴露给开发者。即如果开发的是需要 C 或 C++ 代码的应用,可以使用 Android NDK 直接从原生代码访问某些原生平台库。
Android 的 NDK(下载地址:https://developer.android.google.cn/ndk/downloads/) 提供了 Android 本地 C/C++ 开发环境和工具。
Native 系统库 包括 9 个子系统:
- 系统 C 库 —— 从BSD继承来的标准C系统函数库,专门为基于嵌入式 Linux 设备定制。
- Media Manager 媒体管理 —— 基于PacketVideo的OpenCORE。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
- Surface Manager 图层管理 —— 执行多个应用程序时候,负责管理显示与存取操作间的互动,另外也负责2D绘图与3D绘图进行显示合成。
- LibWebCore —— Web浏览器引擎,驱动Android 浏览器和内嵌的web视图
- SGL —— 基本的2D图形引擎库
- 3D库(OpenGL|ES)—— 基于OpenGL ES 1.0 API 标准实现的3D绘图函数库 。 即 OpenGLESate开放图形库用来支持3D效果。
- FreeType —— 位图和矢量字体渲染,提供点阵字与向量字的描绘与显示
- SQLite —— 小型的关系型数据库引擎 。所有应用程序都可以使用的强大而轻量级的关系数据库引擎
- SSL —— 在Andorid上通信过程中实现握手,即 为数据通信提供支持
这里的 Native系统库 主要包括 init 孵化来的用户空间的守护进程、HAL层以及开机动画等。启动 init 进程(pid=1),是 Linux 系统的用户进程, init 进程是所有用户进程的鼻祖。
进程加载流程:
- init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程;
- init进程还启动 servicemanager(binder服务管家)、 bootanim(开机动画)等重要服务
- init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程(即虚拟机进程), Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。
2.4 Java API Framework 层( Application Framework )
与 系统运行库 被称为 “C库层” 相对应,应用程序框架层往往被冠以 “JAVA库” 的称号。这是因为框架层所提供的组件一般都是以JAVA语言编写而成,他一方面为上层应用程序提供了API接口;另一方面也囊括了不少系统级服务进程的实现,是与Android应用程序开发者关系最直接的一层。开发人员可以完全访问Android系统应用程序,从而复用系统提供的框架API。
通过提供开放的开发平台,Android使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由地利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,很多很多。
开发者可以完全访问和使用 Android 系统提供的框架 API。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行的安全限制)。这一机制允许用户替换组件。
可以通过 Java 语言编写的 API 使用 Android OS 的整个功能集。这些 API 构成了 Android 应用所需的模块,它们可简化核心模块化系统组件和服务的重复使用。
所有的应用程序其实是一组服务和系统,Application Framework 应用程序框架层 共 包括10个部分:
- Activity Manager 活动管理 —— 管理应用程序生命周期,从安装到运行到卸载。提供通用的导航回退( 返回 )功能
- Window Manager 窗口管理、
- Content Providers 内容提供者 —— 使应用程序能访问其他应用程序(如通讯录)的数据,或共享自己的数据
- View System 视图系统 —— 丰富的可扩展的视图集合,用来构建 UI 应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器
- Notification Manager 通知管理 —— 使所有的应用程序能够在状态栏显示自定义提醒。
- Package Manager 包管理、
- Telephony Manager 电话管理、
- Resource Manager 资源管理 —— 提供访问非代码资源,如本地化字符串、图形和布局文件
- Location Manager 位置管理器、
- XMPP Services XMPP 服务
XMPP((Extensible Messaging and Presence Protocol,前称Jabber)是一种以XML为基础的开放式实时通信协议,XMPP网络是基于服务器的(即客户端之间彼此不直接交谈),但是也是分散式的。不像 AOL 实时通或MSN Messenger等服务,XMPP没有中央官方服务器。Jabber.org 的公众服务器上有大量的用户,所以有些人误解了,以为它是官方服务器,不过事实上任何人都可以在自己的域名上运行 XMPP 服务器。
Jabber 识别符(JID)是用户登录时所使用的账号,看起来通常像一个电子邮件地址,如someone@example.com;前半部分为用户名,后半部分为XMPP服务器域名,两个字段以@符号区隔。
假设朱丽叶(juliet@capulet.com)想和罗密欧(romeo@montague.net)通话,他们两人的账号分别在Capulet.com及Montague.net的服务器上。当朱丽叶输入信息并按下发送钮之后,一连串的事件就发生了:
- 朱丽叶的XMPP客户端将她的信息发送到Capulet.com XMPP服务器。
- Capulet.com XMPP服务器打开与Montague.net XMPP服务器的连接。
- Montague.net XMPP服务器将信息寄送给罗密欧。如果他目前不在在线,那么存储信息以待稍后寄送。
进程加载流程:
- Zygote进程,是由init进程通过解析init.rc文件后fork生成的,Zygote进程主要包含:
- 加载ZygoteInit类,注册Zygote Socket服务端套接字
- 加载虚拟机
- 提前加载类preloadClasses
- 提前加载资源preloadResouces
- System Server进程,是由Zygote进程fork而来, SystemServer是Zygote孵化的第一个进程,System Server负责启动和管理整个Java framework,包含ActivityManager,WindowManager,PackageManager,PowerManager等服务。
- Media Server进程,是由init进程fork而来,负责启动和管理整个C++ framework,包含AudioFlinger,Camera Service等服务。
2.5 App 层
简单点说就是:Android的应用运行在Java虚拟机Dalvik之上,即 Java code ---> class ---> dex(Dalvik executable)。
Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。
系统应用可用作用户的应用,以及提供开发者可从其自己的应用访问的主要功能。例如,如果您的应用要发短信,您无需自己构建该功能,可以改为调用已安装的短信应用向您指定的接收者发送消息。
系统应用程序既为用户提供日常生活中常用应用程序,又为提供开发人员提供了可以直接调用系统应用的关键功能。
例如,我们的App想要发送SMS消息(短信),我们不需要重新去写一个短信的功能,而是直接调用系统提供好的Api去向指定的联系人发送短信,甚至,我们可以设定好短信内容,以便减少用户操作。
进程加载流程:
- Zygote进程孵化出的第一个App进程是Launcher,这是用户看到的桌面App;
- Zygote进程还会创建Browser,Phone,Email等App进程,每个App至少运行在一个进程上。
- 所有的App进程都是由Zygote进程fork生成的。
2.6 Syscall && JNI
- Native与Kernel之间有一层系统调用(SysCall)层,见 Linux系统调用(Syscall)原理;
- Java层与Native(C/C++)层之间的纽带JNI,见 Android JNI原理分析。
三、通信方式
无论是Android系统,还是各种Linux衍生系统,各个组件、模块往往运行在各种不同的进程和线程内,这里就必然涉及进程/线程之间的通信。对于IPC(Inter-Process Communication, 进程间通信),Linux现有管道、消息队列、共享内存、套接字、信号量、信号这些IPC机制,Android额外还有Binder IPC机制,Android OS中的Zygote进程的IPC采用的是Socket机制,在上层system server、media server以及上层App之间更多的是采用Binder IPC方式来完成跨进程间的通信。对于Android上层架构中,很多时候是在同一个进程的线程之间需要相互通信,例如同一个进程的主线程与工作线程之间的通信,往往采用的Handler消息机制。
想深入理解Android内核层架构,必须先深入理解Linux现有的IPC机制;对于Android上层架构,则最常用的通信方式是Binder、Socket、Handler,当然也有少量其他的IPC方式,比如杀进程Process.killProcess()采用的是signal方式。下面说说Binder、Socket、Handler:
3.1 Binder
Binder作为Android系统提供的一种IPC机制,无论从系统开发还是应用开发,都是Android系统中最重要的组成,也是最难理解的一块知识点,想了解为什么Android要采用Binder作为IPC机制? 可查看我在知乎上的回答。深入了解Binder机制,最好的方法便是阅读源码,借用Linux鼻祖Linus Torvalds曾说过的一句话:Read The Fucking Source Code。下面简要说说Binder IPC原理。
Binder IPC原理
Binder通信采用c/s架构,从组件视角来说,包含Client、Server、ServiceManager以及binder驱动,其中ServiceManager用于管理系统中的各种服务。
想进一步了解Binder,可查看Binder系列—开篇,Binder系列花费了13篇文章的篇幅,从源码角度出发来讲述Driver、Native、Framework、App四个层面的整个完整流程。根据有些读者反馈这个系列还是不好理解,这个binder涉及的层次跨度比较大,知识量比较广,建议大家先知道binder是用于进程间通信,有个大致概念就可以先去学习系统基本知识,等后面有一定功力再进一步深入研究Binder机制。
Binder原理篇
序号 | 文章名 | 概述 |
---|---|---|
0 | Binder系列—开篇 | Binder概述 |
1 | Binder系列3—启动Service Manager | ServiceManager守护进程 注册和查询服务 |
2 | Binder系列4—获取Service Manager | 获取代理对象BpServiceManager |
3 | Binder系列5—注册服务(addService) | 注册Media服务 |
4 | Binder系列6—获取服务(getService) | 获取Media代理,以及DeathRecipient |
5 | Binder系列7—framework层分析 | framework层服务注册和查询,Binder注册 |
6 | 理解Binder线程池的管理 | Binder的startThreadPool过程 |
7 | 彻底理解Android Binder通信架构 | startService为主线 |
8 | Binder系列10—总结 | Binder的简单总结 |
9 | Binder IPC的权限控制 | clearCallingIdentity/restoreCallingIdentity |
10 | Binder死亡通知机制之linkToDeath | Binder死亡通知机制 |
Binder驱动篇:
1 | Binder系列1—Binder Driver初探 | 驱动open/mmap/ioctl,以及binder结构体 |
2 | Binder系列2—Binder Driver再探 | Binder通信协议,内存机制 |
Binder使用篇:
1 | Binder系列8—如何使用Binder | Native层、Framwrok层自定义Binder服务 |
2 | Binder系列9—如何使用AIDL | App层自定义Binder服务 |
3.2 Socket
Socket通信方式也是C/S架构,比Binder简单很多。在Android系统中采用Socket通信方式的主要有:
- zygote:用于孵化进程,system_server创建进程是通过socket向zygote进程发起请求;
- installd:用于安装App的守护进程,上层PackageManagerService很多实现最终都是交给它来完成;
- lmkd:lowmemorykiller的守护进程,Java层的LowMemoryKiller最终都是由lmkd来完成;
- adbd:这个也不用说,用于服务adb;
- logcatd:这个不用说,用于服务logcat;
- vold:即volume Daemon,是存储类的守护进程,用于负责如USB、Sdcard等存储设备的事件处理。
等等还有很多,这里不一一列举,Socket方式更多的用于Android framework层与native层之间的通信。Socket通信方式相对于binder比较简单,这里省略。
3.3 Handler
Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信,Handler消息机制是由一组MessageQueue、Message、Looper、Handler共同组成的,为了方便且称之为Handler消息机制。
有人可能会疑惑,为何Binder/Socket用于进程间通信,能否用于线程间通信呢?答案是肯定,对于两个具有独立地址空间的进程通信都可以,当然也能用于共享内存空间的两个线程间通信,这就好比杀鸡用牛刀。接着可能还有人会疑惑,那handler消息机制能否用于进程间通信?答案是不能,Handler只能用于共享内存地址空间的两个线程间通信,即同进程的两个线程间通信。很多时候,Handler是工作线程向UI主线程发送消息,即App应用中只有主线程能更新UI,其他工作线程往往是完成相应工作后,通过Handler告知主线程需要做出相应地UI更新操作,Handler分发相应的消息给UI主线程去完成,如下图:
由于工作线程与主线程共享地址空间,即Handler实例对象mHandler位于线程间共享的内存堆上,工作线程与主线程都能直接使用该对象,只需要注意多线程的同步问题。工作线程通过mHandler向其成员变量MessageQueue中添加新Message,主线程一直处于loop()方法内,当收到新的Message时按照一定规则分发给相应的handleMessage()方法来处理。所以说,Handler消息机制用于同进程的线程间通信,其核心是线程间共享内存空间,而不同进程拥有不同的地址空间,也就不能用handler来实现进程间通信。
上图只是Handler消息机制的一种处理流程,是不是只能工作线程向UI主线程发消息呢,其实不然,可以是UI线程向工作线程发送消息,也可以是多个工作线程之间通过handler发送消息。更多关于Handler消息机制文章:
- Android消息机制-Handler(framework篇)
- Android消息机制-Handler(native篇)
- Android消息机制3-Handler(实战)
要理解framework层源码,掌握这3种基本的进程/线程间通信方式是非常有必要,当然Linux还有不少其他的IPC机制,比如共享内存、信号、信号量,在源码中也有体现,如果想全面彻底地掌握Android系统,还是需要对每一种IPC机制都有所了解。
四、核心提纲
通过前面对系统启动的介绍,相信大家对Android系统有了一个整体观。接下来需抓核心、理思路,争取各个击破。后续将持续更新和完善整个大纲,不限于进程、内存、IO、系统服务架构以及分析实战等文章。
当然本站有一些文章没来得及进一步加工,有时间根据大家的反馈,不断修正和完善所有文章,争取给文章,再进一步精简非核心代码,增加可视化图表以及文字的结论性分析。基于Android 6.0的源码,专注于分享Android系统原理、架构分析的原创文章。
建议阅读群体: 适合于正从事或者有兴趣研究Android系统的工程师或者技术爱好者,也适合Android App高级工程师;对于尚未入门或者刚入门的App工程师阅读可能会有点困难,建议先阅读更基础的资料,再来阅读本站博客。
看到Android整个系统架构是如此庞大的, 该问如何学习Android系统, 以下是我自己的Android的学习和研究论,仅供参考如何自学Android。
从整理上来列举一下Android系统的核心知识点概览:
4.1 系统启动系列
Android系统启动-概述: Android系统中极其重要进程:init, zygote, system_server, servicemanager 进程:
序号 | 进程启动 | 概述 |
---|---|---|
1 | init进程 | Linux系统中用户空间的第一个进程, Init.main |
2 | zygote进程 | 所有App进程的父进程, ZygoteInit.main |
3 | system_server进程(上篇) | 系统各大服务的载体, forkSystemServer过程 |
4 | system_server进程(下篇) | 系统各大服务的载体, SystemServer.main |
5 | servicemanager进程 | binder服务的大管家, 守护进程循环运行在binder_loop |
6 | app进程 | 通过Process.start启动App进程, ActivityThread.main |
再来看看守护进程(也就是进程名一般以d为后缀,比如logd,此处d是指daemon的简称), 下面介绍部分守护进程:
- debuggerd
- installd
- lmkd
- logd
4.2 系统稳定性系列
Android系统稳定性主要是异常崩溃(crash)和执行超时(timeout),:
序号 | 文章名 | 概述 |
---|---|---|
1 | 理解Android ANR的触发原理 | 触发ANR的场景以及机理 |
2 | Input系统—ANR原理分析 | input触发ANR的原理 |
3 | 理解Android ANR的信息收集过程 | AMS.appNotResponding过程分析,收集traces |
4 | 解读Java进程的Trace文件 | kill -3 信息收集过程 |
5 | Native进程之Trace原理 | debuggerd -b 信息收集过程 |
6 | WatchDog工作原理 | WatchDog触发机制 |
7 | 理解Java Crash处理流程 | AMS.handleApplicationCrash过程分析 |
8 | 理解Native Crash处理流程 | debuggerd守护进程 |
9 | global reference限制策略 | global reference |
4.3 Android 进程系列
进程/线程是操作系统的魂,各种服务、组件、子系统都是依附于具体的进程实体。深入理解进程机制对于掌握Android系统整体架构和运转机制是非常有必要的,是系统工程师的基本功,下面列举进程相关的文章:
序号 | 文章名 | 概述 |
---|---|---|
1 | 理解Android进程创建流程 | Process.start过程分析 |
2 | 理解杀进程的实现原理 | Process.killProcess过程分析 |
3 | Android四大组件与进程启动的关系 | AMS.startProcessLocked过程分析组件与进程 |
4 | Android进程绝杀技–forceStop | force-stop过程分析彻底移除组件与杀进程 |
5 | 理解Android线程创建流程 | 3种不同线程的创建过程 |
6 | 彻底理解Android Binder通信架构 | 以start-service为线,阐述进程间通信机理 |
7 | 理解Binder线程池的管理 | Zygote fork的进程都默认开启binder线程池 |
8 | Android进程生命周期与ADJ | 进程adj, processState以及lmk |
9 | Android LowMemoryKiller原理分析 | lmk原理分析 |
10 | 进程优先级 | 进程nice,thread priority以及scheduler |
11 | Android进程调度之adj算法 | updateOomAdjLocked过程 |
12 | Android进程整理 | 整理系统的所有进程/线程 |
13 | 解读Android进程优先级ADJ算法 | Android进程ADJ优先级 |
4.4 四大组件系列
对于App来说,Android应用的四大组件Activity,Service,Broadcast Receiver, Content Provider最为核心,接下分别展开介绍:
序号 | 文章名 | 类别 |
---|---|---|
1 | startActivity启动过程分析 | Activity |
2 | 简述Activity生命周期 | Activity |
3 | startService启动过程分析 | Service |
4 | bindService启动过程分析 | Service |
5 | 以Binder视角来看Service启动 | Service |
6 | Android Broadcast广播机制分析 | Broadcast |
7 | 理解ContentProvider原理 | ContentProvider |
8 | ContentProvider引用计数 | ContentProvider |
9 | Activity与Service生命周期 | Activity&&Service |
10 | 简述Activity与Window关系 | Activity&&Window |
11 | 四大组件之综述 | AMS |
12 | 四大组件之ServiceRecord | Service |
13 | 四大组件之BroadcastRecord | Broadcast |
14 | 四大组件之ContentProviderRecord | ContentProvider |
15 | 理解Android Context | Context |
16 | 理解Application创建过程 | Application |
17 | unbindService流程分析 | Service |
18 | 四大组件之ActivityRecord | Activity |
19 | AMS总结(一) | AMS |
4.5 图形系统系列
图形也是整个系统非常复杂且重要的一个系列,涉及WindowManager,SurfaceFlinger服务。
序号 | 文章名 | 类别 |
---|---|---|
1 | WindowManager启动篇 | Window |
2 | WMS之启动窗口篇 | Window |
3 | 以Window视角来看startActivity | Window |
4 | Android图形系统概述 | SurfaceFlinger |
5 | SurfaceFlinger启动篇 | SurfaceFlinger |
6 | SurfaceFlinger绘图篇 | SurfaceFlinger |
7 | Choreographer原理 | Choreographer |
4.6 系统服务篇
再则就是在整个架构中有大量的服务,都是基于Binder来交互的,Android系统服务的注册过程也是在此之上的构建的。计划针对部分核心服务来重点分析:
- AMS服务
- AMS启动过程(一)
- 更多组件篇[见小节4.3]
- Input系统
- Input系统—启动篇
- Input系统—InputReader线程
- Input系统—InputDispatcher线程
- Input系统—UI线程
- Input系统—进程交互
- Input系统—ANR原理分析
- PKMS服务
- PackageManager启动篇
- Installd守护进程
- Alarm服务
- 理解AlarmManager机制
- JobScheduler服务
- 理解JobScheduler机制
- BatteryService
- Android耗电统计算法
- PMS服务
- DropBox服务
- DropBoxManager启动篇
- UserManagerService
- 多用户管理UserManager
- 更多系统服务
4.7 内存&&存储篇
- 内存篇
- Android LowMemoryKiller原理分析
- Linux内存管理
- Android内存分析命令
- 存储篇
- Android存储系统之源码篇
- Android存储系统之架构篇
- Linux驱动篇
- dalvik/art
- 解读Java进程的Trace文件
4.8 工具篇
再来说说Android相关的一些常用命令和工具以及调试手段.
序号 | 文章名 | 类别 |
---|---|---|
1 | 理解Android编译命令 | build |
2 | 理解Android.bp | build |
2 | 性能工具Systrace | systrace |
3 | Android内存分析命令 | Memory |
4 | ps进程命令 | Process |
5 | Am命令用法 | Am |
6 | Pm命令用法 | Pm |
7 | 调试系列1:bugreport源码篇 | bugreport |
8 | 调试系列2:bugreport实战篇 | bugreport |
9 | dumpsys命令用法 | dumpsys |
10 | Android logd日志原理 | logd |
11 | 介绍gdb调试工具 | gdb |
12 | 介绍addr2line调试命令 | addr2line |
4.9 实战篇
下面列举处理过的部分较为典型的案例,供大家参考
序号 | 文章名 | 类别 |
---|---|---|
1 | Binder Driver缺陷导致定屏的案例 | binder |
2 | 深度解读ArrayMap优势与缺陷 | ArrayMap |
3 | 数组越界导致系统重启的案例 | 数组越界 |
4 | 一行Log引发多线程并发问题的案例 | 多线程并发 |
5 | 跑monkey压力测试过程的冻屏案例 | monkey冻屏 |
6 | 深度剖析APP保活案例 | 保活 |
五、结束语
Android系统之博大精深,包括Linux内核、Native、虚拟机、Framework,通过系统调用连通内核与用户空间,通过JNI打通用户空间的Java层和Native层,通过Binder、Socket、Handler等打通跨进程、跨线程的信息交换。只有真正阅读并理解系统核心架构的设计,解决问题和设计方案才能做到心中无剑胜有剑,才能做到知其然知其所以然。当修炼到此,恭喜你对系统有了更高一个层次的理解,正如太极剑法,忘记了所有招式,也就练成了太极剑法。
再回过头去看看那些API,看到的将不再是一行行代码、一个个接口的调用,而是各种信息的传递与交互工作,而是背后成千上万个小蝌蚪的动态执行流。记得《侠客行》里面的龙木二岛主终其一生也无法参透太玄经,石破天却短短数日练成绝世神功,究其根源是龙木二岛主以静态视角去解读太玄经,而石破天把墙壁的图案想象成无数游动的蝌蚪,最终成就绝世神功。一言以蔽之,程序代码是死的,系统运转是活的,要以动态视角去理解系统架构。