### **概述**
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值一樣。
### **一個小實驗**







#### **參考**
[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)的過程分析