原文出處——>[Android應用程序UI硬件加速渲染技術簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/45601143)
Android系統的流暢性一直被拿來與iOS比較,并且認為不如后者。這一方面與Android設備硬件質量參差不齊有關,另一方面也與Android系統的實現有關。例如在3.0前,Android應用程序UI繪制不支持硬件加速。不過從4.0開始,Android系統一直以“run fast, smooth, and responsively”為目標對UI進行優化。本文對這些優化進行簡要介紹和制定學習計劃。
注意,上面我們說Android系統不支持硬件加速的UI 繪制,針對的是Android應用程序2D UI繪制。對于3D UI,例如游戲,一直是支持硬件加速渲染的。此外,從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃、Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃和Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃這三個系列的文章可以知道,Android系統的UI從繪制到顯示到屏幕是分兩步進行的:第一步是在Android應用程序進程這一側進行的;第二步是在SurfaceFlinger進程這一側進行的。前一步將UI繪制一個圖形緩沖區中,并且將該圖形緩沖區交給后一步進行合成以及顯示在屏幕中。其中,后一步的UI合成一直都是以硬件加速方式完成的。
在支持Android應用程序UI硬件加速渲染之前,Android應用程序UI的繪制是以軟件方式進行的,為了更好地理解Android應用程序UI硬件加速渲染技術,我們先回顧在Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃這個系列的文章提及的軟件渲染技術,如圖1所示:
:-: 
圖1 Android應用程序UI軟件渲染過程
在Android應用程序進程這一側,每一個窗口都關聯有一個Surface。每當窗口需要繪制UI時,就會調用其關聯的Surface的成員函數lock獲得一個Canvas,其本質上是向SurfaceFlinger服務Dequeue一個Graphic Buffer。Canvas封裝了由Skia提供的2D UI繪制接口,并且都是在前面獲得的Graphic Buffer上面進行繪制的。繪制完成之后,Android應用程序進程再調用前面獲得的Canvas的成員函數unlockAndPost請求顯示在屏幕中,其本質上是向SurfaceFlinger服務Queue一個Graphic Buffer,以便SurfaceFlinger服務可以對Graphic Buffer的內容進行合成,以及顯示到屏幕上去。
接下來我們再來看Android應用程序UI硬件加速渲染技術,如圖2所示:
:-: 
圖2 Android應用程序UI硬件加速渲染過程
這里我們首先要明確什么是硬件加速渲染,其實就是通過GPU來進行渲染。GPU作為一個硬件,用戶空間是不可以直接使用的,它是由GPU廠商按照Open GL規范實現的驅動間接進行使用的。也就是說,如果一個設備支持GPU硬件加速渲染,那么當Android應用程序調用Open GL接口來繪制UI時,Android應用程序的UI就是通過硬件加速技術進行渲染的。因此,在接下來的描述中,我們提及到GPU、硬件加速和Open GL時,它們表達的意思都是等價的。
從圖2可以看到,硬件加速渲染和軟件渲染一樣,在開始渲染之前,都是要先向SurfaceFlinger服務Dequeue一個Graphic Buffer。不過對硬件加速渲染來說,這個Graphic Buffer會被封裝成一個ANativeWindow,并且傳遞給Open GL進行硬件加速渲染環境初始化。在Android系統中,ANativeWindow和Surface可以是認為等價的,只不過是ANativeWindow常用于Native層中,而Surface常用于Java層中。另外,我們還可以將ANativeWindow和Surface看作是像Skia和Open GL這樣圖形渲染庫與操作系統底層的圖形系統建立連接的一個橋梁。
Open GL獲得了一個ANativeWindow,并且進行了硬件加速渲染環境初始化工作之后,Android應用程序就可以調用Open GL提供的API進行UI繪制了,繪制出來內容就保存在前面獲得的Graphic Buffer中。當繪制完畢,Android應用程序再調用libegl庫提供的一個eglSwapBuffer接口請求將繪制好的UI顯示到屏幕中,其本質上與軟件渲染過程是一樣的,都是向SurfaceFlinger服務Queue一個Graphic Buffer,以便SurfaceFlinger服務可以對Graphic Buffer的內容進行合成,以及顯示到屏幕上去。
關于Android應用程序UI的硬件加速渲染過程中涉及到Open GL環境初始化和繪制的簡化版本,可以參考前面Android系統的開機畫面顯示過程分析一文提到的Android系統開機動畫的實現。在Android系統的開機畫面顯示過程分析這篇文章中,開機動畫其實是由一個/system/bin/bootanimation程序實現的。這個程序可以看成是一個沒有使用Android SDK來開發的一個Native應用程序。
在這個系列的文章中,我們將通過Android 5.0的源碼來分析Android應用程序UI的硬件加速渲染技術。不過為了更好地理解Android 5.0的硬件加速渲染實現,我們有必要先了解從Android 3.0以來,Android應用程序UI硬件加速渲染的進化歷史:
1. Android 3.0,也就是Honeycomb版本,開始引用OpenGLRenderer圖形渲染庫,支持Android應用程序UI可選地使用硬件加速渲染。
2. Android 4.0,也就是Ice Cream Sandwich版本,要求設備默認支持Android應用程序UI硬件加速渲染,并且增加一個TextureView控件,該控件直接支持以Open GL紋理的形式來繪制UI。
3. Android 4.1、4.2和4.3,也就是Jelly Bean版本,加入了Project Butter(黃油計劃)的特性,包括:A. 通過Vsync信號來同步UI繪制和動畫,使得它們可以獲得一個達到60fps的固定的幀率;B. 三緩沖支持,改善GPU和CPU之間繪制節奏不一致的問題;C. 將用戶輸入,例如touch event,同步到下一個Vsync信號到來時再處理;D. 預測用戶的touch行為,以獲得更好的交互響應;E. 每次用戶touch屏幕時,進行CPU Input Boost,以便減少處理延時。
4. Android 4.4,也就是KitKat版本,一方面通過優化內存使用,另一方面是可選地支持使用ART運行時替換Dalvik虛擬機,來提高應用程序的運行效率,使得其UI更流暢。
5. Android 5.0,也就是Lollipop版本,ART運行時引進了Compacting GC,進一步優化了Android應用程序的內存使用,并且ART運行時正式替換了Dalvik虛擬機,同時,Android應用程序增加了一個Render Thread,專門負責UI渲染和動畫顯示。
從Android應用程序UI硬件加速渲染的進化歷史可以看出,Android系統確實是在踐行"run fast, smooth, and responsively"的宏偉計劃,并且也是做到了。
有了前面的基礎知識之后,我們接下來再來Android 5.0的窗口和動畫是如何通過硬件加速技術來渲染的,如圖3所示:
:-: 
圖3 Android應用程序窗口和動畫的硬件加速渲染框架
在Android應用程序窗口中,每一個View都抽象為一個Render Node,而且如果一個View設置有Background,這個Background也被抽象為一個Render Node。這是由于在OpenGLRenderer庫中,并沒有View的概念,所有的一切可繪制的元素都抽象為一個Render Node。
每一個Render Node都關聯有一個Display List Renderer。這里又涉及到另外一個概念——Display List。注意,這個Display List不是Open GL里面的Display List,不過它們在概念上是差不多的。Display List是一個繪制命令緩沖區。也就是說,當View的成員函數onDraw被調用時,我們調用通過參數傳遞進來的Canvas的drawXXX成員函數繪制圖形時,我們實際上只是將對應的繪制命令以及參數保存在一個Display List中。接下來再通過Display List Renderer執行這個Display List的命令,這個過程稱為Display List Replay。
引進Display List的概念有什么好處呢?主要是兩個好處。第一個好處是在下一幀繪制中,如果一個View的內容不需要更新,那么就不用重建它的Display List,也就是不需要調用它的onDraw成員函數。第二個好處是在下一幀中,如果一個View僅僅是一些簡單的屬性發生變化,例如位置和Alpha值發生變化,那么也無需要重建它的Display List,只需要在上一次建立的Display List中修改一下對應的屬性就可以了,這也意味著不需要調用它的onDraw成員函數。這兩個好處使用在繪制應用程序窗口的一幀時,省去很多應用程序代碼的執行,也就是大大地節省了CPU的執行時間。
注意,只有使用硬件加速渲染的View,才會關聯有Render Node,也就才會使用到Display List。我們知道,目前并不是所有的2D UI繪制命令都是GPU可以支持的。這一點具體可以參考官方說明文檔:http://developer.android.com/guide/topics/graphics/hardware-accel.html。 對于使用了GPU不支持的2D UI繪制命令的View,只能通過軟件方式來渲染。具體的做法是將創建一個新的Canvas,這個Canvas的底層是一個Bitmap,也就是說,繪制都發生在這個Bitmap上。繪制完成之后,這個Bitmap再被記錄在其Parent View的Display List中。而當Parent View的Display List的命令被執行時,記錄在里面的Bitmap再通過Open GL命令來繪制。
另一方面,對于前面提到的在Android 4.0引進的TextureView,它也不是通過Display List來繪制。由于它的底層實現直接就是一個Open GL紋理,因此就可以跳過Display List這一中間層,從而提高效率。這個Open GL紋理的繪制通過一個Layer Renderer來封裝。Layer Renderer和Display List Renderer可以看作是同一級別的概念,它們都是通過Open GL命令來繪制UI元素的。只不過前者操作的是Open GL紋理,而后者操作的是Display List。
我們知道,Android應用程序窗口的View是通過樹形結構來組織的。這些View不管是通過硬件加速渲染還是軟件渲染,或者是一個特殊的TextureView,在它們的成員函數onDraw被調用期間,它們都是將自己的UI繪制在Parent View的Display List中。其中,最頂層的Parent View是一個Root View,它關聯的Root Node稱為Root Render Node。也就是說,最終Root Render Node的Display List將會包含有一個窗口的所有繪制命令。在繪制窗口的下一幀時,Root Render Node的Display List都會通過一個Open GL Renderer真正地通過Open GL命令繪制在一個Graphic Buffer中。最后這個Graphic Buffer被交給SurfaceFlinger服務進行合成和顯示。
以上就是Android應用程序窗口和動畫的硬件加速渲染框架,里面提到的Render Thread還需要進一步解釋。Render Thread是在Android 5.0中引進的,它用來分擔Android應用程序的Main Thread的工作。在Android 5.0之前,Android應用程序的Main Thread不僅負責渲染UI,還負責處理用戶輸入。通過引進Render Thread,我們就可以將UI渲染工作從Main Thread釋放出來,交由Render Thread來處理,從而也使得Main Thread可以更專注高效地處理用戶輸入,這樣使得在提高UI繪制效率的同時,也使得UI具有更高的響應性。
Main Thread與Render Thread的交互模型如圖4所示:
:-: 
圖4 Android應用程序Main Thread與Render Thread的交互模型
Main Thread主要是負責調用View的成員函數onDraw來構造它們的Display List,然后在下一個Vsync信號到來時,再通過一個Render Proxy對象向Render Thread發出一個drawFrame命令。Render Thread內部有一個Task Queue,從Main Thread發送過來的drawFrame命令就會保存在Render Thread的Task Queue,等待Render Thread處理。
上面分析的應用程序UI繪制機制還沒有涉及到動畫。當一個View需要以動畫的形式顯示時,我們可以通過調用這個View的成員函數animate獲得一個ViewPropertyAnimator。ViewPropertyAnimator可以通過兩種方式來顯示動畫。第一種方式是舊的方式,動畫的每一幀由Main Thread進行計算,然后再由Render Thread進行渲染。第二種方式是Android 5.0引進的,Main Thread將動畫注冊到Render Thread中去,然后由Render Thread計算和顯示動畫的每一幀。第二種方式在動畫的顯示期間,完全不需要Main Thread參與,不過前提是Main Thread不想參與。如果Main Thread需要參與,例如,Main Thread想在動畫開始之前,將View的Layer Type設置為LAYER_TYPE_HARDWARE,以便它可以以Open GL的Frame Buffer Object(FBO)的形式進行渲染,或者Main Thread想偵聽動畫的每一幀顯示,那么就不能將動畫的計算和顯示完全交給Render Thread來做了。將動畫的計算和顯示完全交給Render Thread來做的好處就是使得動畫的顯示不影響Main Thread響應用戶的其它輸入。
上面提到,在顯示一個View的動畫之前,Main Thread可以將View的Layer Type設置為LAYER_TYPE_HARDWARE,這樣View可以以FBO的形式進行渲染更,這是通過調用與View關聯的ViewPropertyAnimator的成員函數withLayer來實現的。這是對動畫顯示的另一種優化。回憶TextureView的特點,它是直接通過Open GL紋理來繪制,這樣可以省去Display List這一中間步驟。同樣的,對于Layer Type為LAYER_TYPE_HARDWARE的View,它將直接通過FBO來實現,這樣也是可以提高渲染效率。等到動畫結束的時候,ViewPropertyAnimator會將View的Layer Type將恢復為原來設置的類型。
上面描述的兩種動畫顯示優化涉及到Main Thread與Render Thread的交互如圖5所示:

圖5 Android應用程序Main Thread與Render Thread的動畫交互模型
從View獲得一個用來顯示動畫的ViewPropertyAnimator之后,調用它的成員函數withLayer,就會導致Main Thread向Render Thread發送一個buildLayer的命令。Render Thread執行這個buildLayer的命令的時候,就會為與View關聯的Render Node設置一個Layer。以后Render Thread就以Layer的方式,即FBO的方式,來渲染View的動畫。
另一方面,如果一個View的動畫顯示不需要Main Thread的參與,那么從View獲得一個ViewPropertyAnimator會將動畫注冊到Render Thread里面的一個AnimatorManager中。Render Thread通過AnitmatorManager檢測注冊到它里面的動畫是否還沒有結束。如果還沒有結束,那么Render Thread就自動地計算和顯示動畫的下一幀,直到動畫顯示結束為止。
至此,Android應用程序UI的硬件加速渲染涉及到的關鍵概念我們就介紹完成了,接下來我們還會按照以下五個情景進一步分析它的實現:
1. Android應用程序UI硬件加速渲染的環境初始化過程分析;
2. Android應用程序UI硬件加速渲染的預加載資源地圖集創建過程分析;
3. Android應用程序UI硬件加速渲染的Display List構建過程分析;
4. Android應用程序UI硬件加速渲染的Display List渲染過程分析;
5. Android應用程序UI硬件加速渲染的動畫執行過程分析。
其中,第二個情景是第四個情景涉及到的一個重要優化,因此我們將它單獨列出來分析。通過這五個情景的學習,我們就可以深入地掌握Android應用程序UI的硬件加速渲染技術了,敬請期待!
- 前言
- 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)的過程分析