### **概述**
Android应用开发的哲学是把一切都看作是组件。把应用程序组件化的好处是降低模块间的耦合性,同时提高模块的复用性。Android的组件设计思想与传统的组件设计思想最大的区别在于,前者不依赖于进程。也就是说,进程即使由于内存紧张被强行杀掉了,但是运行在里面的组件还是存在的。这样就可以在组件再次需要使用时,原地满血复活,就像什么都没发生过一样。这种设计思想非常适合内存较小的移动设备。
理解Android组件设计思想,对Android应用程序架构会有更好的认识。这一节讲Android组件化设计的背景、理念、原则,以及Android在OS级别上提供的组件化支持,其中还会包含一个实验来验证这种组件化设计思想,可以对Android系统有一个高层次的抽象理解。
* 组件化背景
* 组件化设计
* 组件化支持
* 一个小实验
### **组件化背景**
#### **从PC客户端应用程序说起**
* 开发者角度
* 复杂,同时兼顾UI、交互和业务逻辑
* 运行载体是进程
* 进程只有一个入口点—main
* 使用者角度
* 流畅的UI、友好的交互、正确的结果
* 不知进程是何物
#### **PC客户端应用程序开发的任务**
* 满足用户的需求
* 降低程序复杂度 -- 组件化
#### PC客户端应用程序组件化之后
* 开发者角度
* 运行载体仍然是进程
* 进程仍然是只有一个入口点—main
* 使用者角度
* 流畅的UI、友好的交互、正确的结果
* 不知进程是何物
#### **结论**
应用程序组件化前后,用户对其运行载体(进程)没有概念,但是开发者来说,组件化后的应用程序仍然是和进程直接关联的,也就是说,进程一旦不存在,程序和组件也随之灰飞烟灭!
#### **再说移动客户端应用程序**
* 与PC客户端应用程序一样,包含UI、交互和业务等复杂逻辑
* 与PC客户端应用程序一样,用户的需求是流畅的UI、友好的交互、正确的结果
* 运行在低频率CPU、小容量内存、小面积屏幕设备上
#### **设备特性对移动客户端应用程序的影响**
* 低频率CPU
影响程序运行速度,尤其是程序启动速度,因为用户对程序启动时间最为敏感
* 小容量内存
影响同时运行的程序的数量,而且系统会在内存紧张时杀进程,以便回收内存
* 小面积屏幕
单窗口操作模式,导致用户需要频繁地切换程序或者重新打开程序
#### **移动客户端应用程序开发的任务**
* 满足用户的需求
* 降低程序复杂度
#### **组件化是降低移动端应用程序复杂度的不二选择,但需进一步考虑以下两个事实**:
* 设备特性的影响
* 系统杀进程时,被杀进程里面的组件如何处理?
* 程序切换和重新打开时,如可提高程序启动速度?
* 用户不关心进程
* 是否可以将组件与进程进行剥离?
### **组件化设计**
#### **基本思想**
Everything is component
#### **具体实现**
* 程序由组件组成
* 组件与进程剥离
* 组件皆程序入口
#### **程序由组件组成**
* Activity:前台交互
* Service:后台计算
* Broadcast Receiver:广播通信
* Content Provider:数据封装
此四种组件对客户端应用程序进行了很好的抽象,QT的signal-slot,COM的连接点,都是广播的例子
#### **组件与进程剥离**
* 组件关闭时,进程可以继续存在
提高重新启动时的速度
* 进程关闭时,组件可以继续存在
保护被杀进程里面的组件
#### **组件皆程序入口**
* Activity -- onCreate
* Service -- onCreate
* Broadcast Receiver -- onReceive
* Content Provider -- onCreate
由于组件已与进程剥离,因此不再有进程入口的概念,只有组件入口的概念
#### **将组件与进程进行剥离,使得进程对组件透明,听起来很好,但是如何解决以下四个问题?**
* 谁来负责组件的启动和关闭?
* 谁来维护组件的状态?
* 谁来管理组件运行时所需要的进程?
* 组件之间如何进行通信?
### **组件化支持**
#### **操作系统级别的组件化支持**
* Activity Manager Service
* Binder
* Low Memory Killer
#### **Activity Manager Service**
* 启动组件
组件启动时,检查其所要运行在的进程是否已创建。如果已经创建,就直接通知它加载组件。否则,先将该进程创建起来,再通知它加载组件。
* 关闭组件
组件关闭时,其所运行在的进程无需关闭,这样就可以让组件重新打开时得到快速启动。
* 维护组件状态
维护组件在运行过程的状态,这样组件就可以在其所运行在的进程被回收的情况下仍然继续生存。
* 进程管理
在适当的时候主动回收空进程和后台进程,以及通知进程自己进行内存回收
1. 组件的UID和Process Name唯一决定了其所要运行在的进程。
2. 每次组件onStop时,都会将自己的状态传递给AMS维护。
3. AMS在以下四种情况下会调用trimApplications来主动回收进程:
A. activityStopped
B. setProcessLimit
C. unregisterReceiver
D. finishReceiver
4. WMS也会主动回收进程:
WindowManagerService在处理窗口的过程中发生Out Of Memroy时,会调用reclaimSomeSurfaceMemoryLocked来回收某些Surface占用的内存,reclaimSomeSurfaceMemoryLocked的逻辑如下所示:
(1).首先检查有没有泄漏的Surface,即那些Session已经不存在但是还没有销毁的Surface,以及那些宿主Activity已经不可见但是还没有销毁的Surface。如果存在的话,就将它们销毁即可,不用KillPids。
(2).如果不存在没有泄漏的Surface,那么那些存在Surface的进程都有可能被杀掉,这是通过KillPids来实现的。
**KillPids**:
* (1). 找中候选进程的最大oom_adj值。
* (2). 如果找到的最大oom_adj值恰好位于[ProcessList.HIDDEN_APP_MIN_ADJ(9), ProcessList.HIDDEN_APP_MAX_ADJ(15)]之间,那么就将最大oom_adj值修改为ProcessList.HIDDEN_APP_MIN_ADJ,表示要将所有后台进程都杀掉。
* (3). 如果此时杀进程是不安全的,并且找到的最大oom_adj值比ProcessList.SERVICE_ADJ还要小,那么就将将最大oom_adj值设置为ProcessList.SERVICE_ADJ,避免重要进程被杀掉。
* (4). oom_adj值大于等于前面找到的最大oom_adj值的候选进程都将被杀掉。
**trimApplications**:
* (1). 杀掉Package已经被Remove了的进程,属于无用进程
* (2). 调用updateOomAdjLocked更新所有进程的oom_adj
**updateOomAdjLocked -- all**:
* (1). 根据进程运行状态来更新进程的oom_adj。更新顺序是从最近使用到最近不使用的。如果一个进程是后台进程,那么按照这个顺序进行更新,就意味着最近越是不使用的后台进程,它获得的oom_adj值就越大。后台进程(以及空进程)的oom_adj取值范围[ProcessList.HIDDEN_APP_MIN_ADJ(9), ProcessList.HIDDEN_APP_MAX_ADJ(15)]
* (2),如果空进程超过限制,那么最近越是不使用的空进程,就越会被杀掉。
* (3). 如果后台进程超过限制,那么最近越是不使用的后台进程,就越会被杀掉。
* (4). 通知进程ScheduleTrimMemory。
updateOomAdjLocked -- single:
* (1). 调用computeOomAdjLocked计算oom_adj。
* (2). 计算oom_adj之后,如果ShchedGroup发生改变,并且变成了THREAD_GROUP_BG_NONINTERACTIVE调度组,那么进程就会被杀掉。
**computeOomAdjLocked**:
* (1). ProcessList.FOREGROUND_APP_ADJ(0): 前台进程、有InstrumentionClass的进程、正在接收广播的进程、正在执行Service Callback的进程、正在运行有外部依赖的Content Provider的进程
* (2). ProcessList.VISIBLE_APP_ADJ(1): 有Activity是Visible的进程
* (3). ProcessList.PERCEPTIBLE_APP_ADJ(2):有Activity是Pausing、Paused或者Stopping状态的进程、有Service被设置为Foreground的进程、被设置为Foreground的进程。
* (4). ProcessList.HEAVY_WEIGHT_APP_ADJ(3):被设置为重量级App的进程。
* (5). ProcessList.BACKUP_ADJ(4):正在执行备份任务的进程。
* (6). ProcessList.SERVICE_ADJ(5):最近有活动的Service的进程。
* (7). ProcessList.HOME_APP_ADJ(6):Home App进程。
* (8). ProcessList.PREVIOUS_APP_ADJ(7):前一个显示UI的进程。
* (9). ProcessList.SERVICE_B_ADJ(8):oom_adj值等于ProcessList.SERVICE_ADJ的进程超过限制时,最近越是不使用的进程的oom_adj值就会由ProcessList.SERVICE_ADJ变成ProcessList.SERVICE_B_ADJ。
**PS**:
* (1). 如果一个进程运行有绑定至另外一个进程(Client)的Content Provider或者Service,并且client进程的oom_adj值比该进程的oom_adj小,那么该进程的oom_adj值就会被设置为client进程的oom_adj值,但是不能超过ProcessList.FOREGROUND_APP_ADJ。
* (2). ProcessList.PERSISTENT_PROC_ADJ(-12):被设置为persistent的进程,如PhoneApp,不参与oom_adj更新计算。
* (3). ProcessList.SYSTEM_ADJ(-16):System进程,不参与oom_adj更新计算。
#### **Binder**
* 为组件间通信提供支持
* 进程间
* 进程内
* 高效的IPC机制
* 进程间的组件通信时,通信数据只需一次拷贝
* 进程内的组件通信时,跳过IPC进行直接的通信
传统的IPC,通信数据需要执行两次,一次是从源进程的用户空间拷贝到内核空间,二次是从内核空间拷贝到目标进程的用户空间
### **Low Memory Killer**
* 内存紧张时回收进程
由于组件与进程是剥离的,因此进程回收不会影响组件的生命周期
* 从低优先级进程开始回收
* Empty Process
* Hidden Process
* Perceptible Process
* Visible Process
* Foreground Process
**备注:**
1. 每一个APP进程都有一个oom_adj值,该值是根据进程所运行的组件计算出来的,值越小,优先级就越级。
2. Init和System Server进程的oom_adj等于-16,是最高的,保证不会被杀死。
3. PhoneApp具有persist属性,它的oom_adj被设置为-12,也能保证不会被杀死。
4. 可以通过`/proc/<pid>oom_adj`文件查看进程的oom_adj值。
5. 在Linux内核中,子进程的oom_adj值等于父进程的oom_adj,也就是说,Android里面的Native进程的oom_adj值与fork它的进程的oom_adj值一样。
### **一个小实验**
![](https://box.kancloud.cn/6b0a21741ce83aee9bb14f9e02eaec5b_730x427.jpg)
![](https://box.kancloud.cn/11d7df7d87dfe78872979ca93ee81c0c_376x535.jpg)
![](https://box.kancloud.cn/2a6bb88d43b77719b55c64f1a74e2dc8_558x498.jpg)
![](https://box.kancloud.cn/9312ef0cf2b9ba90789c4702ff961435_648x379.jpg)
![](https://box.kancloud.cn/c77136efc5ba8eaf15202a9f46692f2b_557x510.jpg)
![](https://box.kancloud.cn/c965bf242f8563dee2137547d511bf9a_376x535.jpg)
![](https://box.kancloud.cn/a27568f6388372fe758ad74adf42cfed_561x487.jpg)
#### **参考**
[Google安卓开发培训入门指南](http://developer.android.com/training/index.html)
[Google安卓开发应用组件](http://developer.android.com/guide/components/index.html)
[Android 源代码](http://source.android.com/source/index.html)
[Android 接口和架构](http://source.android.com/devices/index.html)
- 前言
- Android组件设计思想
- Android源代码开发和调试环境搭建
- Android源代码下载和编译
- Android源代码情景分析法
- Android源代码调试分析法
- 手把手教你为手机编译ROM
- 在Ubuntu上下载、编译和安装Android最新源代码
- 在Ubuntu上下载、编译和安装Android最新内核源代码(Linux Kernel)
- 如何单独编译Android源代码中的模块
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序
- 在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务
- 在Ubuntu上为Android系统内置Java应用程序测试Application Frameworks层的硬件服务
- Android源代码仓库及其管理工具Repo分析
- Android编译系统简要介绍和学习计划
- Android编译系统环境初始化过程分析
- Android源代码编译命令m/mm/mmm/make分析
- Android系统镜像文件的打包过程分析
- 从CM刷机过程和原理分析Android系统结构
- Android系统架构概述
- Android系统整体架构
- android专用驱动
- Android硬件抽象层HAL
- Android应用程序组件
- Android应用程序框架
- Android用户界面架构
- Android虚拟机之Dalvik虚拟机
- Android硬件抽象层
- Android硬件抽象层(HAL)概要介绍和学习计划
- Android专用驱动
- Android Logger驱动系统
- Android日志系统驱动程序Logger源代码分析
- Android应用程序框架层和系统运行库层日志系统源代码分析
- Android日志系统Logcat源代码简要分析
- Android Binder驱动系统
- Android进程间通信(IPC)机制Binder简要介绍和学习计划
- 浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路
- 浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析
- Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析
- Android Ashmem驱动系统
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析
- Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析
- Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析
- Android应用程序进程管理
- Android应用程序进程启动过程的源代码分析
- Android系统进程Zygote启动过程的源代码分析
- Android系统默认Home应用程序(Launcher)的启动过程源代码分析
- Android应用程序消息机制
- Android应用程序消息处理机制(Looper、Handler)分析
- Android应用程序线程消息循环模型分析
- Android应用程序输入事件分发和处理机制
- Android应用程序键盘(Keyboard)消息处理机制分析
- Android应用程序UI架构
- Android系统的开机画面显示过程分析
- Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
- SurfaceFlinger
- Android系统Surface机制的SurfaceFlinger服务
- SurfaceFlinger服务简要介绍和学习计划
- 启动过程分析
- 对帧缓冲区(Frame Buffer)的管理分析
- 线程模型分析
- 渲染应用程序UI的过程分析
- Android应用程序与SurfaceFlinger服务的关系
- 概述和学习计划
- 连接过程分析
- 共享UI元数据(SharedClient)的创建过程分析
- 创建Surface的过程分析
- 渲染Surface的过程分析
- Android应用程序窗口(Activity)
- 实现框架简要介绍和学习计划
- 运行上下文环境(Context)的创建过程分析
- 窗口对象(Window)的创建过程分析
- 视图对象(View)的创建过程分析
- 与WindowManagerService服务的连接过程分析
- 绘图表面(Surface)的创建过程分析
- 测量(Measure)、布局(Layout)和绘制(Draw)过程分析
- WindowManagerService
- WindowManagerService的简要介绍和学习计划
- 计算Activity窗口大小的过程分析
- 对窗口的组织方式分析
- 对输入法窗口(Input Method Window)的管理分析
- 对壁纸窗口(Wallpaper Window)的管理分析
- 计算窗口Z轴位置的过程分析
- 显示Activity组件的启动窗口(Starting Window)的过程分析
- 切换Activity窗口(App Transition)的过程分析
- 显示窗口动画的原理分析
- Android控件TextView的实现原理分析
- Android视图SurfaceView的实现原理分析
- Android应用程序UI硬件加速渲染
- 简要介绍和学习计划
- 环境初始化过程分析
- 预加载资源地图集服务(Asset Atlas Service)分析
- Display List构建过程分析
- Display List渲染过程分析
- 动画执行过程分析
- Android应用程序资源管理框架
- Android资源管理框架(Asset Manager)
- Asset Manager 简要介绍和学习计划
- 编译和打包过程分析
- Asset Manager的创建过程分析
- 查找过程分析
- Dalvik虚拟机和ART虚拟机
- Dalvik虚拟机
- Dalvik虚拟机简要介绍和学习计划
- Dalvik虚拟机的启动过程分析
- Dalvik虚拟机的运行过程分析
- Dalvik虚拟机JNI方法的注册过程分析
- Dalvik虚拟机进程和线程的创建过程分析
- Dalvik虚拟机垃圾收集机制简要介绍和学习计划
- Dalvik虚拟机Java堆创建过程分析
- Dalvik虚拟机为新创建对象分配内存的过程分析
- Dalvik虚拟机垃圾收集(GC)过程分析
- ART虚拟机
- Android ART运行时无缝替换Dalvik虚拟机的过程分析
- Android运行时ART简要介绍和学习计划
- Android运行时ART加载OAT文件的过程分析
- Android运行时ART加载类和方法的过程分析
- Android运行时ART执行类方法的过程分析
- ART运行时垃圾收集机制简要介绍和学习计划
- ART运行时Java堆创建过程分析
- ART运行时为新创建对象分配内存的过程分析
- ART运行时垃圾收集(GC)过程分析
- ART运行时Compacting GC简要介绍和学习计划
- ART运行时Compacting GC堆创建过程分析
- ART运行时Compacting GC为新创建对象分配内存的过程分析
- ART运行时Semi-Space(SS)和Generational Semi-Space(GSS)GC执行过程分析
- ART运行时Mark-Compact( MC)GC执行过程分析
- ART运行时Foreground GC和Background GC切换过程分析
- Android安全机制
- SEAndroid安全机制简要介绍和学习计划
- SEAndroid安全机制框架分析
- SEAndroid安全机制中的文件安全上下文关联分析
- SEAndroid安全机制中的进程安全上下文关联分析
- SEAndroid安全机制对Android属性访问的保护分析
- SEAndroid安全机制对Binder IPC的保护分析
- 从NDK在非Root手机上的调试原理探讨Android的安全机制
- APK防反编译
- Android视频硬解稳定性问题探讨和处理
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android应用程序安装过程源代码分析
- Android应用程序启动过程源代码分析
- 四大组件源代码分析
- Activity
- Android应用程序的Activity启动过程简要介绍和学习计划
- Android应用程序内部启动Activity过程(startActivity)的源代码分析
- 解开Android应用程序组件Activity的"singleTask"之谜
- Android应用程序在新的进程中启动新的Activity的方法和过程分析
- Service
- Android应用程序绑定服务(bindService)的过程源代码分析
- ContentProvider
- Android应用程序组件Content Provider简要介绍和学习计划
- Android应用程序组件Content Provider应用实例
- Android应用程序组件Content Provider的启动过程源代码分析
- Android应用程序组件Content Provider在应用程序之间共享数据的原理分析
- Android应用程序组件Content Provider的共享数据更新通知机制分析
- BroadcastReceiver
- Android系统中的广播(Broadcast)机制简要介绍和学习计划
- Android应用程序注册广播接收器(registerReceiver)的过程分析
- Android应用程序发送广播(sendBroadcast)的过程分析