01-Android底層原理|Android的各個渲染框架和Android圖層渲染原理

語言: CN / TW / HK

前言

Android

Android 系統 由美國的Google公司髮型。它作為智慧移動終端搭載系統之一,自誕生以來,就備受關注。至今為止已經迭代了9+代了,國內不少手機開發廠商(如小米)等都是基於Android 系統進行改造,然後搭載在自己的產品中去的

Android 底層核心空間以 【Linux Kernel 】作為基石。上層使用者空間由 Native系統庫虛擬機器執行環境框架層組成,通過系統呼叫(Syscall)連通系統的【核心空間】與【使用者空間】。\ 對於使用者空間主要採用 C++ 和 Java 程式碼編寫,通過 JNI技術 打通使用者空間的 Java層Native層(C++/C) ,從而連通整個系統。

我們今天就Android頁面渲染原理為主題,對Android系統的渲染框架和渲染流水線展開討論,以為後期在專案實施過程中做技術選型做知識儲備!!那就讓我們進入今天的正題吧!!!

概述

本文主要對Android頁面渲染原理展開討論。在討論本文主題之前,我們需要進行一定的知識鋪墊。先帶大家簡單回顧一下計算機圖形渲染原理。若是您有一定的`計算機圖形學基礎,可以忽略前期的知識準備直接從本文的第二節開始閱讀。

本文總共有以下幾個章節:\ 一、鋪墊知識 - 計算機圖形渲染原理 ; - 移動終端螢幕成像與卡頓原理; 二、安卓的檢視層和視窗\ 三、安卓系統的各個渲染框架和渲染流水線\ 四、總結\ 推薦閱讀\ 相關閱讀

一、鋪墊知識

安卓系統的圖形渲染原理其實在核心部分都是和計算機圖形學的計算機圖形渲染原理原理一樣的。所以我們在瞭解安卓的檢視系統和其2D、3D渲染框架渲染流水線之前,我們需要進入我的這篇文章:計算機圖形渲染原理進行一定的知識準備。

連結附帶的文章中,我們可以瞭解到“智慧硬體CPUGPU的設計理念以及兩者之間的效能差異”、“計算機圖形渲染晶片GPU的誕生史”、"圍繞GPU工作的3D圖形渲染庫(OpenGL、DirectX等)、圖形學相關的專業術語和OpenGL工作的渲染流水線"、“螢幕成像的電子束CRT掃描原理”、“螢幕成像原理”等諸多相關的核心要點。

您若是不想關注CPU、GPU。直接瞭解移動裝置的螢幕成像原理也可以閱讀我這一份專門為移動而寫的簡約版:移動終端螢幕成像與卡頓。\ 在這篇文章中,我們可以分別從兩個維度去關注,第一個就是系統成像遇到的Bug問題,第二個就是解決問題的解決方案. 幾個要點可以簡單的歸納為: - 問題:"螢幕撕裂Screen Tearing""掉幀Jank"檢視成像切換銜接失誤導致的畫面空白 - 解決方案:"Vsync""Double Buffering""Triple Buffering"

總結,我們這裡主要關注螢幕成像的整個渲染流水線,以便於我們後面對安卓的影象渲染原理展開討論:\ ①獲取圖層渲染資料→②GPU加工成畫素資料→③幀緩衝器(儲存畫素資訊)→④影片控制器讀取快取→數→⑤數模轉換、顯示器顯示

我們今天的主題就是主要關注第一個環節。入手點分為幾個: - 安卓系統的檢視層(Layer)和檢視視窗(Window)以及安卓系統中的各個圖形渲染框架(2D/3D) - 安卓系統的渲染流水線 - 安卓系統的事件機制

二、安卓的檢視層和檢視視窗

2.1 安卓顯示系統的三駕馬車:View,AMS,WMS

在開發過程中,我們編碼繪製介面時,我們只關心單個介面,但是執行工程,專案在裝置上顯示的時候,可能就有多個介面了。\ 做過Android開發的同學應該都知道,我們需要繼承一個Activity,用Activity呈現我們的介面。Activity的職責之一是對介面生命週期的管理,這也就伴隨了對檢視視窗的管理。這中間就涉及了兩個Android中兩個主要的服務,AMS(ActivityManagerService)和WMS(WindowManagerService)。\ View,AMS,WMS可以說是整個上層顯示系統的三駕馬車

在Android中,一個視窗用一個Surface描述。多個視窗(視窗不一定都是Activity),需要同時顯示,我們就需要將多個視窗進行合併。這就需要顯示系統中重量級的服務SurfaceFlinger,Surfaceflinger控制視窗的合成,將多個視窗合併成一個,再送到LCD。

Surfaceflinger是Native的服務,Surfaceflinger中怎麼去描述一個視窗呢?Surfaceflinger採用圖層的概念,即Layer。SurfaceFlinger合成,就是基於Display HAL的實現,將多個Layer合併。關於Display HAL,各個廠商的實現就千差萬別了。

2.2 SurfaceUI

總的來說 Android 系統採用一種稱為 Surface 的 UI 架構為應用程式提供使用者介面。 - 在 Android 應用程式中,每一個 Activity 元件都關聯有一個或者若干個視窗每一個視窗都對應有一個 Surface 介面很簡單,拆開來看,包含微信、懸浮工具箱、通知欄、底部虛擬按鍵欄。\ 上層每一個介面,其實都對應SufaceFlinger裡的一個Surface物件,上層將自己的內容繪製在對應的Surface內, - 有了這個 Surface 之後,應用程式就可以在上面渲染視窗的 UI。最終這些已經繪製好了的 Surface 都會被統一 提交給 Surface 管理服務 SurfaceFlinger 進行合成,最後顯示在螢幕上面。 - 接著,SufaceFlinger需要將所有上層對應的Surface內的圖形進行合成,具體看下圖: 1. 對應上層的一個Window(對話方塊、Activity、狀態列) 2. 作為上層圖形繪製的畫板 3. Canvas是畫筆,上層通過呼叫Canvas的API向Surface上繪製圖形 4. Surface內部存在多個緩衝區,形成一個BufferQueue

  • 無論是應用程式,還是 SurfaceFlinger,都可以利用 GPU 等硬體來進行 UI 渲染,以便獲得更流暢的 UI。

一句話來概括一下 Android 應用程式顯示的過程就是:

Android 應用程式呼叫 SurfaceFlinger 服務 把 "經過測量、佈局和繪製後的 Surface" 通過"圖形渲染框架" 藉助 GPU 渲染,最後數模轉換顯示到螢幕上。

2.3 安卓圖形介面的背後重要成員

我們先了解幾個重要的成員:

  • Surface: Android 應用的每個視窗對應一個畫布(Canvas),即 Surface

    • 可以理解為 Android 應用程式的一個視窗。
    • Surface 是一個介面,供生產方與使用方交換緩衝區。
  • SurfaceView: SurfaceView 是一個元件,可用於在 View 層次結構中嵌入其他合成層。

    • SurfaceView 採用與其他 View 相同的佈局引數,因此可以像對待其他任何 View 一樣對其進行操作,但 SurfaceView 的內容是透明的。
    • 當 SurfaceView 的 View 元件即將變得可見時,框架會要求 SurfaceControl 從 SurfaceFlinger 請求新的 Surface。
  • Surface Buffer: 圖形的傳遞是通過Buffer作為載體,Surface是對Buffer的進一步封裝。

    • 也就是說Surface內部具有多個Buffer供上層使用,如何管理這些Buffer呢?
    • Surface內部提供一個BufferQueue,與上層和SurfaceFlinger形成一個生產者消費者模型,上層對應Producer,SurfaceFlinger對應Consumer。
    • 三者通過Buffer產生聯絡,每個Buffer都有四種狀態:
      • Free:可被上層使用
      • Dequeued:出列,正在被上層使用
      • Queued:入列,已完成上層繪製,等待SurfaceFlinger合成
      • Acquired:被獲取,SurfaceFlinger正持有該Buffer進行合成
    • Buffer的一次轉移過程大致為:
      • 從BufferQueue轉移到上層
      • 上層繪製完成再放回BufferQueue
      • 接著SurfaceFlinger再拿去合成
      • 最後又放回BufferQueue
      • 如此迴圈,形成一個Buffer被迴圈使用的過程。
  • EGLSurface 和 OpenGL ES: OpenGL ES (GLES) 定義了用於與 EGL 結合使用的圖形渲染 API。

    • EGI 是一個規定如何通過作業系統建立和訪問視窗的庫
    • 要繪製紋理多邊形的時候使用 GLES 呼叫;
    • 要將渲染放到螢幕上的時候使用 EGL 呼叫;
  • WindowManager: WindowManager 會控制視窗物件,它們是用於容納檢視物件的容器。

    • 視窗物件始終由 Surface 物件提供支援。
    • WindowManager 會監督生命週期、輸入和聚焦事件、螢幕方向、轉換、動畫、位置、變形、Z 軸順序以及視窗的許多其他方面。
    • WindowManager 會將所有視窗元資料傳送到 SurfaceFlinger,以便 SurfaceFlinger 可以使用這些資料在螢幕上合成 Surface。
  • SurfaceFlinger: Android 系統服務。 負責管理 Android 系統的幀緩衝區。

    1. 分配圖形緩衝區
    2. 合成圖形緩衝區
    3. 管理 VSYNC 事件
    4. SurfaceFlinger 接受來自多個源的資料緩衝區,然後將它們進行合成併發送到顯示屏。
    5. WindowManager 為 SurfaceFlinger 提供緩衝區和視窗元資料,而 SurfaceFlinger 可使用這些資訊將 Surface 合成到螢幕
    6. SurfaceFlinger 可通過兩種方式接受緩衝區:通過 BufferQueue 和 SurfaceControl,或通過 ASurfaceControl。
  • ViewRootImpl: 用來控制視窗的渲染,以及用來與 WindowManagerServiceSurfaceFlinger 通訊。

  • BufferQueue: BufferQueue 類將可生成圖形資料緩衝區的元件(生產方)連線到接受資料以便進行顯示或進一步處理的元件(使用方)。

  • 幾乎所有在系統中移動圖形資料緩衝區的內容都依賴於 BufferQueue。

  • View和ViewGroup

    • View是Android中所有控制元件的基類,不管是簡單的TextView,Button還是複雜的LinearLayout和ListView,它們的共同基類都是View。它表示一個空白的矩形區域。
    • View類還有一個很重要的子類:ViewGroup,但是ViewGroup通常作為其他元件的容器使用。
    • Android的所有UI元件都是建立在View、ViewGroup基礎之上的,Android採用了“組合器”模式來設計View和ViewGroup:ViewGroup是View的子類,因此ViewGroup也可以被當做View使用。
    • 對於一個Android應用的圖形使用者介面來說,ViewGroup作為容器來盛裝其他元件,而ViewGroup裡除了可以包含普通View元件之外,還可以再次包含ViewGroup元件
    • 在View中,具備它的位置、顏色等屬性。同時也管理著點選、觸控手勢等事件機制
    • 我們可以引入一張圖,來理解一下從View到圖形渲染框架再到Surface的關係
  • Canvas: Canvas是一個2D圖形API,是Android View樹實際的渲染者。

    • Canvas又可分為Skia軟體繪製和hwui硬體加速繪製。
    • Android4.0之前預設是Skia繪製,該方式完全通過CPU完成繪圖指令,並且全部在主執行緒操作,在複雜場景下單幀容易超過16ms導致卡頓。
    • 從Android4.0開始,預設開啟硬體加速渲染,而且5.0開始把渲染操作拆分到了兩個執行緒:

      • 主執行緒和渲染執行緒,主執行緒負責記錄渲染指令
      • 渲染執行緒負責通過OpenGL ES完成渲染,兩個執行緒可以併發執行。
    • 除了Canvas,開發者還可以在非同步執行緒直接通過OpenGL ES進行渲染,一般適用於遊戲、影片播放等獨立場景。

  • OpenGL ES OpenGL是 c-based 的3D渲染API

  • Vulkan: Vulkan 是一種用於高效能 3D 圖形的低開銷、跨平臺 API。

  • 與 OpenGL ES 一樣,Vulkan 提供用於在應用中建立高質量實時圖形的工具。
  • VulKan是用來替換OpenGL的。它不僅支援3D,也支援2D,同時更加輕量級

  • Skia Skia 是Android底層的2D圖形庫

三、安卓系統的各個渲染框架和渲染流水線

3.1 安卓渲染的演變

瞭解Android系統對渲染的不斷優化歷史,對於理解渲染很有幫助。

Android 4.1

引入了project butter黃油計劃:Vsync、三倍緩衝、choreography編舞者。

Android 5.0

引入了RenderThread執行緒(該執行緒是系統在framework層維護),把之前CPU直接操作繪製指令(OpenGL/vulkan/skia)部分,交給了單獨的渲染執行緒。減少主執行緒的工作。即使主執行緒卡住,渲染也不受影響。

Android 7.0

引入了Vulkan支援。 OpenGL是3D渲染API,VulKan是用來替換OpenGL的。它不僅支援3D,也支援2D,同時更加輕量級。

3.2 圖形渲染框架:OpenGL、Vulkan、Skia

  • OpenGL: 是一種跨平臺的3D圖形繪製規範介面。OpenGL EL則是專門針對嵌入式裝置,如手機做了優化。

  • Vulkan: 跟OpenGL相同功能,不過它同時支援3D、2D,比OpenGL更加的輕量、效能更高。

  • Skia: skia是影象渲染庫,2D圖形繪製自己就能完成。3D效果(依賴硬體)由OpenGL、Vulkan、Metal支援。它不僅支援2D、3D,同時支援CPU軟體繪製和GPU硬體加速。Android、flutter都是使用它來完成繪製。

3.3 圖形渲染流水線

在介紹各個渲染框架協作下的渲染流水線之前,先引入一張官方系統的圖:\

這幅圖大致描述了圖形資料的流轉: - OpenGL ES、MediaPlayer等生產者生產圖形資料到Surface - Surface通過IGraphicBufferProducerGraphicBuffer跨程序傳輸給消費者SurfaceFlinger, - SurfaceFlinger根據WMS提供的視窗資訊合成所有的Layer(對應於Surface),具體的合成策略由hwcomposerHAL模組決定並實施, - 最後也是由該模組送顯到Display,而Gralloc模組則負責分配圖形緩衝區。

圖中概念的解釋: - Image Stream Producers(圖形流的生產者): 可產生graphic buffers的生產者. 例如OpenGL ES, Canvas 2D, mediaserver的影片解碼器.

  • Image Stream Consumers(圖形流的消費者): 最場景的消費者便是SurfaceFlinger,它使用OpenGL和Hardware Composer來組合一組surfaces.

    • OpenGL ES應用能消費圖形流, 比如camera app消費camera預覽圖形流;
    • 非OpenGL ES應用也能消費, 比如ImageReader類
  • Window Manager: 用於管理window, 這是一組view的容器. WM將手機的window元資料(包括螢幕放心,z-order等)資訊傳送給SurfaceFlinger,因此SurfaceFlinger 能使用這些資訊來合成surfaces,並輸出到顯示裝置.

  • Hardware Composer(硬體混合渲染器): 這是顯示子系統的硬體抽象層。

    • 顯示子系統的硬體抽象實現。SurfaceFlinger 可以將某些合成工作委託給 Hardware Composer,以分擔 OpenGL 和 GPU 上的工作量。
    • SurfaceFlinger 只是充當另一個 OpenGL ES 客戶端。因此,在 SurfaceFlinger 將一個或兩個緩衝區合成到第三個緩衝區中的過程中,它會使用 OpenGL ES。這樣使合成的功耗比通過 GPU 執行所有計算更低。
  • HAL: 硬體抽象層。把圖形資料展示到裝置螢幕

    • Hardware Composer HAL 則進行另一半的工作,並且是所有 Android 圖形渲染的核心。
    • Hardware Composer 必須支援事件,其中之一是 VSYNC(另一個是支援即插即用 HDMI 的熱插拔)
  • Gralloc: 全稱為graphics memory allocator,影象記憶體分配器, 用於圖形生產這來請求分配記憶體.

從這張圖我們可以知道,安卓圖形渲染設計理念有一個生成者消費者模式,而他們中間的橋樑就是Buffer Data:

生產者和消費者執行在不同的程序. - 生產者請求一塊空閒的快取區:dequeueBuffer() - 生產者填充快取區並返回給佇列: queueBuffer() - 消費者獲取一塊快取區: acquireBuffer() - 消費者使用完畢,則返回給佇列: releaseBuffer()

我們前面引入那張官方圖我們可以把它變成有層次感的另一幅圖來理解一下渲染過程和其中涉及到的幾個圖形框架:\

大體上,應用開發者可以通過兩種方式將影象繪製到螢幕上:

  • Canvas
  • OpenGL ES

Canvas是一個2D圖形API,是Android View樹實際的渲染者。 - Canvas又可分為Skia軟體繪製和Hwui硬體加速繪製。 - Android4.0之前預設是Skia繪製,該方式完全通過CPU完成繪圖指令,並且全部在主執行緒操作,在複雜場景下單幀容易超過16ms導致卡頓。 - 從Android4.0開始,預設開啟硬體加速渲染,而且5.0開始把渲染操作拆分到了兩個執行緒:主執行緒和渲染執行緒,主執行緒負責記錄渲染指令,渲染執行緒負責通過OpenGL ES完成渲染,兩個執行緒可以併發執行。

除了Canvas,開發者還可以在非同步執行緒直接通過OpenGL ES進行渲染,一般適用於遊戲、影片播放等獨立場景。

從應用側來看,不管是Canvas,還是OpenGL ES,最終渲染到的目標都是Surface。現在比較流行的跨平臺UI框架Flutter在Android平臺上也是直接渲染到Surface。

  • Surface是一個視窗,例如:一個Activity是一個Surface、一個Dialog也是一個Surface,承載了上層的圖形資料,與SurfaceFlinger側的Layer相對應。

    • Native層Surface實現了ANativeWindow結構體,在建構函式中持有一個IGraphicBufferProducer,用於和BufferQueue進行互動。
    • BufferQueue是連線Surface和Layer的紐帶,當上層圖形資料渲染到Surface時,實際是渲染到了BufferQueue中的一個GraphicBuffer,然後通過IGraphicBufferProducerGraphicBuffer提交到BufferQueue,讓SurfaceFlinger進行後續的合成顯示工作。

    • SurfaceFlinger負責合成所有的Layer並送顯到Display,這些Layer主要有兩種合成方式:

      • OpenGL ES:把這些圖層合成到FrameBuffer,然後把FrameBuffer提交給hwcomposer完成剩餘合成和顯示工作。
      • hwcomposer:通過HWC模組合成部分圖層和FrameBuffer,並顯示到Display。

至於OpenGL ES 或者Skia 它的詳細工作流程,本文不鋪展開來討論,若是希望瞭解可以關注我的相關閱讀推薦閱讀

四、總結

本文簡單介紹了 安卓系統的 UI組成 和背後的一些相關概念。簡單介紹了幾個圖形渲染框架和渲染流程。

本文尚未深入討論的話題有: 1. 在渲染過程中,SurfaceFlinger的工作原理 2. 渲染過程中,UI執行緒、RenderThread執行緒、SurfaceFlinger之間的資料如何傳遞 3. 對圖層渲染框架SkiaOpenGLESVulkan的使用 4. ......

推薦閱讀

相關閱讀(共計14篇文章)

iOS相關專題

webApp相關專題

跨平臺開發方案相關專題

階段性總結:Native、WebApp、跨平臺開發三種方案效能比較

Android、HarmonyOS頁面渲染專題

小程式頁面渲染專題

總結