Surface 與 BufferQueue 機(jī)制

  • Surface 到底是什么?它和 View/Window 的關(guān)系是什么?
  • App 繪制的像素?cái)?shù)據(jù)是如何存儲(chǔ)在 Surface 中的?
  • Surface 是如何跨進(jìn)程把數(shù)據(jù)傳遞給 SurfaceFlinger 的?

Surface 的定義

Surface 不是 “顯示組件”,而是 「一塊可繪制的內(nèi)存緩沖區(qū)(Buffer)的抽象封裝」。

  • 通俗理解:Surface 是 App 寫(xiě)給 “畫(huà)布” 的 “畫(huà)板”,App 只負(fù)責(zé)往畫(huà)板上畫(huà)畫(huà)(寫(xiě)入像素?cái)?shù)據(jù)),但不負(fù)責(zé)把畫(huà)板掛到墻上(顯示到屏幕);

  • 技術(shù)本質(zhì):Surface 內(nèi)部持有 BufferQueue 的「生產(chǎn)者(Producer)」端,通過(guò)它向緩沖區(qū)寫(xiě)入數(shù)據(jù)。

Surface 與 Window/View 的關(guān)系

  • 1 個(gè) Window 對(duì)應(yīng) 1 個(gè) Surface:每個(gè) Activity/Dialog/ 狀態(tài)欄都對(duì)應(yīng)一個(gè) Window,每個(gè) Window 會(huì)創(chuàng)建一個(gè)專屬的 Surface(通過(guò) WindowManager 申請(qǐng));

  • View 依賴 Surface 繪制:所有 View 的 onDraw() 最終都是通過(guò) Canvas 把數(shù)據(jù)寫(xiě)入所屬 Window 的 Surface 緩沖區(qū);

  • Surface 與 ViewRootImpl 綁定:ViewRootImpl 是 Surface 和 View 樹(shù)的橋梁,負(fù)責(zé)把 View 繪制的內(nèi)容同步到 Surface 中。

Activity 啟動(dòng) → WindowManager 創(chuàng)建 Window
  ↓
WindowManager 向 SurfaceFlinger 申請(qǐng) Surface
  ↓
SurfaceFlinger 創(chuàng)建 BufferQueue,并返回「生產(chǎn)者」給 App 層
  ↓
App 層封裝生產(chǎn)者為 Surface 對(duì)象,綁定到 ViewRootImpl
  ↓
ViewRootImpl 把 Surface 傳遞給 Canvas,供 View 繪制
  • 關(guān)鍵結(jié)論:Surface 的創(chuàng)建是跨進(jìn)程的,由 SurfaceFlinger 主導(dǎo),App 層只持有 “寫(xiě)入數(shù)據(jù)的權(quán)限”。

BufferQueue - 緩沖區(qū)的「生產(chǎn)者 - 消費(fèi)者」模型

BufferQueue 是連接 App 和 SurfaceFlinger 的核心機(jī)制,本質(zhì)是 「環(huán)形緩沖區(qū)隊(duì)列」,遵循生產(chǎn)者 - 消費(fèi)者設(shè)計(jì)模式:

  • 生產(chǎn)者(Producer):App 層(Surface 持有),負(fù)責(zé)往緩沖區(qū)寫(xiě)入繪制好的像素?cái)?shù)據(jù);

  • 消費(fèi)者(Consumer):SurfaceFlinger 層,負(fù)責(zé)從緩沖區(qū)讀取數(shù)據(jù),進(jìn)行圖層合成。

BufferQueue 的核心作用

  • 解耦 App 繪制和 SurfaceFlinger 合成:App 繪制的速度和 SurfaceFlinger 合成的速度可以不一致,通過(guò)緩沖區(qū)隊(duì)列緩沖;

  • 復(fù)用緩沖區(qū):避免頻繁創(chuàng)建 / 銷(xiāo)毀內(nèi)存緩沖區(qū),減少內(nèi)存抖動(dòng)和性能消耗;

  • 同步數(shù)據(jù):保證 SurfaceFlinger 讀取的緩沖區(qū)是 “完整繪制完成” 的,避免讀取到半拉子數(shù)據(jù)。

BufferQueue 的工作流程(60Hz 屏幕為例)

1. 初始狀態(tài):BufferQueue 有 N 個(gè)空緩沖區(qū)(通常 2-3 個(gè));
2. App 向 BufferQueue 請(qǐng)求一個(gè)空緩沖區(qū)(dequeueBuffer);
3. App 通過(guò) Canvas 把繪制內(nèi)容寫(xiě)入該緩沖區(qū);
4. App 把寫(xiě)好的緩沖區(qū)送回隊(duì)列(queueBuffer),標(biāo)記為“就緒”;
5. SurfaceFlinger 從隊(duì)列取出就緒的緩沖區(qū)(acquireBuffer);
6. SurfaceFlinger 合成該緩沖區(qū)的數(shù)據(jù)到最終幀;
7. SurfaceFlinger 把用完的緩沖區(qū)放回隊(duì)列(releaseBuffer),標(biāo)記為“空”;
8. 重復(fù)步驟 2-7,每 16.6ms 執(zhí)行一次(60Hz 屏幕)。

雙緩沖 / 三緩沖機(jī)制

  • 雙緩沖:BufferQueue 有 2 個(gè)緩沖區(qū),一個(gè)供 App 寫(xiě)入,一個(gè)供 SurfaceFlinger 讀取,避免 “寫(xiě)一半被讀” 的問(wèn)題;

  • 三緩沖:當(dāng) App 繪制耗時(shí)超過(guò) 16.6ms 時(shí),第三個(gè)緩沖區(qū)可以承接下一次繪制,減少掉幀(比如 120Hz 屏幕常用三緩沖)。

Surface + BufferQueue 核心

// Surface 中的生產(chǎn)者邏輯(App 層)
public class Surface {
    private final SurfaceControl mSurfaceControl;
    private final BufferQueueProducer mProducer; // 生產(chǎn)者

    // 申請(qǐng)空緩沖區(qū)
    public long dequeueBuffer(BufferItem item, long timeout) {
        return mProducer.dequeueBuffer(item, timeout);
    }

    // 提交寫(xiě)好的緩沖區(qū)
    public int queueBuffer(long bufferId, int flags) {
        return mProducer.queueBuffer(bufferId, flags);
    }
}

// SurfaceFlinger 中的消費(fèi)者邏輯(Native 層簡(jiǎn)化)
class SurfaceFlinger {
    private BufferQueueConsumer mConsumer; // 消費(fèi)者

    // 獲取就緒的緩沖區(qū)
    status_t acquireBuffer(BufferItem* item, nsecs_t timeout) {
        return mConsumer->acquireBuffer(item, timeout);
    }

    // 釋放用完的緩沖區(qū)
    status_t releaseBuffer(int slot, uint64_t frameNumber) {
        return mConsumer->releaseBuffer(slot, frameNumber);
    }
}

Surface → SurfaceFlinger 的數(shù)據(jù)傳遞

跨進(jìn)程通信的核心:Binder

Surface 持有的 BufferQueueProducer 是 Binder 接口,SurfaceFlinger 持有的 BufferQueueConsumer 是 Binder 服務(wù)端:

  • App 層調(diào)用 queueBuffer() 時(shí),通過(guò) Binder 把緩沖區(qū)的「句柄(Handle)」傳遞給 SurfaceFlinger(而非直接傳遞像素?cái)?shù)據(jù),避免內(nèi)存拷貝);

  • SurfaceFlinger 通過(guò)句柄直接訪問(wèn)緩沖區(qū)內(nèi)存(基于共享內(nèi)存 Ashmem),無(wú)需拷貝,效率極高。

數(shù)據(jù)傳遞完整流程

App 層:View.onDraw() → Canvas 寫(xiě)入像素?cái)?shù)據(jù)
  ↓
Canvas 把數(shù)據(jù)寫(xiě)入 Surface 持有的 BufferQueue 緩沖區(qū)
  ↓
Surface.queueBuffer() → 通過(guò) Binder 把緩沖區(qū)句柄發(fā)給 SurfaceFlinger
  ↓
SurfaceFlinger.acquireBuffer() → 獲取緩沖區(qū)句柄,訪問(wèn)共享內(nèi)存
  ↓
SurfaceFlinger 合成該緩沖區(qū)(與其他 Surface 的緩沖區(qū))→ 輸出到屏幕
  • 關(guān)鍵結(jié)論:像素?cái)?shù)據(jù)存儲(chǔ)在共享內(nèi)存中,只傳遞句柄,不拷貝數(shù)據(jù),這是 Android 渲染性能的核心優(yōu)化點(diǎn)。

SurfaceView vs TextureView

普通 View 依賴 Window 的 Surface 繪制,而高頻繪制場(chǎng)景(視頻、游戲、直播)需要更高效的 Surface 載體:

image.png

問(wèn)題

  • 為什么 SurfaceFlinger 不直接讀取 App 內(nèi)存中的像素?cái)?shù)據(jù),而是通過(guò) BufferQueue 共享內(nèi)存?

  • 為什么 SurfaceView 適合高頻繪制場(chǎng)景,而普通 View 不適合?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容