你有沒有想過,錄屏軟件是怎麼獲取到屏幕內容的?

歡迎你們關注個人微信公衆號——「簡靜慢」,除了技術文章,我還會在裏面分享一些平常的思考,歡迎一塊兒交流。bash

前言

前段時間 Android R 發佈了 Beta 版本,同時帶來原生用戶心心念唸的功能——錄屏,雖然這個功能在別的 Android 定製 ROM,像 MIUI,在好幾年前已經就有了。是錄屏這個功能是很難實現嗎?爲何谷歌遲遲不願在 Android 上這個功能呢?微信

再者,目前十分火爆的手機直播,大概能夠分爲兩種形式:一種是讓觀衆看到手機攝像頭拍到的內容;另外一種是讓觀衆看到手機屏幕的內容。然後者,其實能夠理解爲另一種形式的「錄屏」。app

那麼,「錄屏」在咱們平常生活中這麼常見的功能,你是否思考過,錄屏背後的原理是什麼?錄屏軟件又是怎麼獲取到屏幕的畫面內容的呢?composer

閱讀完本文,你能夠了解到:ide

  1. 在 App 渲染合成中的狀態與事務(State and Transaction)
  2. 錄屏背後的功臣——Virtual Display 的核心接口以及 SurfaceFlinger 是如何發現,處理 VirtualDisplay
  3. 錄屏的原理以及完整的數據流傳輸

若是你對這些內容感興趣,那就接着看下去吧。若是對這些冗長的分析感到頭疼,想要直接看到結論,能夠直接放到最後面的總結。那咱們開始吧。函數

VirtualDisplay 簡介

在目前的 Android 中,支持多種屏幕(Display,後文提到的 Display 都是指以下的各類屏幕)類型:fetch

  • 內置的主屏幕
  • 經過 HDMI 鏈接的外接屏幕
  • 虛擬屏幕(Virtual Display)

前兩種都是有具體的物理屏幕設備的,而與之相反的 Virtual Display 則沒有,是由 SurfaceFlinger 模擬出來的,一大做用就是給前面反覆提到的「錄屏」提供基礎設施。ui

核心接口

前面提到錄屏背後用到的都是 VirtualDisplay,這裏分別點一下 C++ 和 Java 中與 VirtualDisplay 相關的核心接口:this

C++

在 Android 中有一個 screenrecord 的命令,這個命令是用純 C++ 寫的,源碼路徑在:frameworks/av/cmds/screenrecord/,經過這份谷歌官方的源碼咱們能夠一窺 native 層實現錄屏的原理(其實 Android 很早以前就支持錄屏了哈哈)。其中的核心代碼:atom

static status_t prepareVirtualDisplay(const DisplayInfo& mainDpyInfo,
        const sp<IGraphicBufferProducer>& bufferProducer,
        sp<IBinder>* pDisplayHandle) {
    sp<IBinder> dpy = SurfaceComposerClient::createDisplay(
            String8("ScreenRecorder"), false /*secure*/);

    SurfaceComposerClient::Transaction t;
    t.setDisplaySurface(dpy, bufferProducer);
    ......
    t.apply();
複製代碼

這裏面涉及到三個最爲核心的接口:

  1. SurfaceComposerClient::createDisplay()
    sp<IBinder> SurfaceComposerClient::createDisplay(const String8& displayName, bool secure) {
         return ComposerService::getComposerService()->createDisplay(displayName,
                 secure);
    }
    複製代碼

實現很是簡單,經過 Binder 調用 SurfaceFlinger 端的 createDisplay() 來建立 VirtualDisplay。而至於 SurfaceFlinger 是如何建立 VirtualDisplay 的,後面會詳細分析。

  1. SurfaceComposerClient::Transaction::setDisplaySurface()
status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token,
      const sp<IGraphicBufferProducer>& bufferProducer) {
      
    ......
    DisplayState& s(getDisplayState(token));
    s.surface = bufferProducer;
    s.what |= DisplayState::eSurfaceChanged;
    return NO_ERROR;
}
複製代碼

將上面建立的 VirtualDisplay 和本地的 IGraphicBufferProducer (Client 端經過 createBufferQueue() 能夠得到 BufferQueue 的 IGraphicBufferProducerIGraphicBufferConsumer)關聯起來。注意這裏的 DisplayState::eSurfaceChanged,會是後面一系列流程重要的標誌位。

  1. SurfaceComposerClient::Transaction::apply()

這個函數也很是重要,App 側的改變都須要這個函數通知給 SurfaceFlinger 側。

在後文會對三個接口作深刻的分析。

Java

在 Android Framework 中有一個類 OverlayDisplayAdapter,這個類是方便 Framework 開發者建立模擬輔助顯示設備,一樣也有 C++ 提到的三個核心接口。事實上,Java 端的這些接口其實都是對作了一些封裝,最終經過 JNI 調用到 native 層,最終的實現都是在 SurfaceFlinger,這裏就不過多描述,詳細能夠參考 @夕月風 大佬在簡書上的博客:《Android P 圖形顯示系統(四) Android VirtualDisplay解析》

狀態與事務

狀態

DisplayState

frameworks/native/libs/gui/include/gui/LayerState.h 裏定義:

struct DisplayState {
    enum {
        eOrientationDefault = 0,
        eOrientation90 = 1,
        eOrientation180 = 2,
        eOrientation270 = 3,
        eOrientationUnchanged = 4,
        eOrientationSwapMask = 0x01
    };

    enum {
        eSurfaceChanged = 0x01,
        eLayerStackChanged = 0x02,
        eDisplayProjectionChanged = 0x04,
        eDisplaySizeChanged = 0x08
    };

    DisplayState();
    void merge(const DisplayState& other);

    uint32_t what;
    sp<IBinder> token;
    sp<IGraphicBufferProducer> surface;
    uint32_t layerStack;

    uint32_t orientation;
    Rect viewport;
    Rect frame;

    uint32_t width, height;

    status_t write(Parcel& output) const;
    status_t read(const Parcel& input);
};
複製代碼

這個結構體是在 Client 端(即 App 側)定義的,裏面描述了 Client 端關於 Display 全部狀態的集合,包括了 Display 的方向,Display 裏 Surface 改變,LayerStack 改變等(對應了上面的 enum 變量),what 是狀態的集合,全部的狀態能夠經過 「與」 操做合併到一塊兒(仔細看上面上面的 enum 變量的值,每個狀態都佔用了十六進制的一位)。

DisplayDeviceState

frameworks/native/services/surfaceflinger/DisplayDevice.h

struct DisplayDeviceState {
    bool isVirtual() const { return !displayId.has_value(); }

    int32_t sequenceId = sNextSequenceId++;
    std::optional<DisplayId> displayId;
    sp<IGraphicBufferProducer> surface;
    uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
    Rect viewport;
    Rect frame;
    uint8_t orientation = 0;
    uint32_t width = 0;
    uint32_t height = 0;
    std::string displayName;
    bool isSecure = false;

private:
    static std::atomic<int32_t> sNextSequenceId;
};
複製代碼

DisplayDeviceState 是在 Server 端(即 SurfaceFlinger 側)定義的, 不光名字跟前面的 DisplayDevice 很像,內部成員也十分地相似。那麼這兩個類有什麼關係呢?

我的是這麼理解的,這兩個類實際上是 App 側和 SurfaceFlinger 側對於 Display 狀態 的不一樣表示,前面提到的 SurfaceComposerClient::Transaction::apply() 的做用一個就是將 DisplayState 傳遞給 DisplayDeviceState,後文原理分析中會有詳細說明。

還有一個點很是重要,DisplayDeviceState 是如何區分對應的 Display 是否爲 VirtualDisplay 的呢?答案就在 displayId 的類型中 —— std::optionalstd::optional 是 C++ 17 新引入的新特性,做用是方便表示或者處理一個變量「可能爲空」的狀態,若是在之前,咱們會選擇使用相似 NULLnull 或者 -1 這種特殊值來標記,可是如今,std::optional 給出了一種更加方便的方案,這裏不作過多的語法描述。

DisplayDeviceState 中的 isVirtual() 就是用來判斷該 DisplayDeviceState 對應的 Display 是否爲 VirtualDisplay,而判斷的依據就是 displayId.has_value(), 而對於 Virtual Display 來講,是不會對其 displayId 進行賦值的,而主顯和外顯則會賦值,於是 !displayId.has_value() 爲 true,從而能夠判斷出 Display 是否爲 VirtualDisplay。

DisplayToken

上面提到的 DisplayStateDisplayDeiveState 都是須要跟具體 Display 設備(無論是不是 VirtualDisplay)綁定。而 DisplayToken 就是這些 state 類型跟具體 Display 設置鏈接的橋樑。 DisplayToken 其實只是一個 IBinder 類型的變量,而且其值自己是沒有意義的,只是用來作索引罷了。

事務

每個 VSYNC 之間, Display 或者是各個 Layer 可能都會發生不少變化,這些變化被 SurfaceFlinger 打包在一塊兒統一處理,統稱爲 Transaction——事務,在目前的 Android Q 中,上面涉及到各類 state,在 SurfaceFlinger 端被打包成以下的事務,用枚舉變量描述:

enum {
    eTransactionNeeded = 0x01,
    eTraversalNeeded = 0x02,
    eDisplayTransactionNeeded = 0x04,
    eDisplayLayerStackChanged = 0x08,
    eTransactionFlushNeeded = 0x10,
    eTransactionMask = 0x1f,
};
複製代碼

這些事務在 SurfaceFlinger::handleTransaction() 中被處理,而這個函數在每次 VSYNC-sf 觸發 SurfaceFlinger 合成的時候都會調用一次。這就很像古代皇帝天天上早朝通常,handleTransaction() 就像皇上身邊的那個太監喊了一聲,

"有事啓奏,無事退朝"

若是上個 VSYNC 內 Client 端有 State 的變化,那麼就會被 SurfaceFlinger 經過 handleTransaction() 知曉而且被處理,如同有大臣在底下說,

"臣有事啓奏"

而後皇帝一天忙碌的工做就開始了。

而這些事務會被統一記錄在 mTransactionFlags 這個變量中,經過 setTransactionFlags()peekTransactionFlags()getTransactionFlags 來更新/獲取當前的 mTransactionFlags 的值:

uint32_t SurfaceFlinger::peekTransactionFlags() {
    return mTransactionFlags;
}

// 注意:
// 這裏的 fetch_and() 和下面的 fetch_or(),這兩個的函數值都是修改前的 mTransactionFlags,這一點很是重要
uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) {
    return mTransactionFlags.fetch_and(~flags) & flags;
}

uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags) {
    return setTransactionFlags(flags, Scheduler::TransactionStart::NORMAL);
}

uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
                                             Scheduler::TransactionStart transactionStart) {
    uint32_t old = mTransactionFlags.fetch_or(flags);
    mVsyncModulator.setTransactionStart(transactionStart);
    if ((old & flags)==0) { // wake the server up
        signalTransaction();
    }
    return old;
}
複製代碼

peekTransactionFlags()getTransactionFlags() 從函數名看都是獲取 mTransactionFlags 的值,可是其實有很大的區別。 peekTransactionFlags() 只是簡單地將當前的 mTransactionFlags 直接返回。 而 getTransactionFlags() 則否則,它表面的做用是判斷並返回當前的 mTransactionFlags 是否包含指定的 TransactionFlag(經過原來的 mTransactionFlags 跟傳進來的 flag 作**"與"**操做)。 可是 getTransactionFlags() 會將原來 mTransactionFlags 的值,修改成只包含傳進來的 TransactionFlags 的位,其他位都會置爲 0。 說句題外話,從上面的說明其實能夠看到, peekTransactionFlags()getTransactionFlags() 這兩個函數的命名很是具備迷惑性,很容易帶來認知上的誤區。若是讓我來命名的話,那麼 peekTransactionFlags() 應該命名爲 getTransactionFlags(),而 getTransactionFlags() 更加應該命名爲 checkTransactionFlags()

State

看到這你可能會很奇怪,狀態前面不是已經說了嗎?爲何又蹦出了一個 State?其實這裏的 State 是一個新的類,而以前在 講解 fps 計算原理 提到了的 mCurrentStatemDrawingState,類型就是 State

StateSurfaceFlinger 這個類裏面的一個內部類:

class State {
public:
    explicit State(LayerVector::StateSet set) : stateSet(set), layersSortedByZ(set) {}
    ......
    const LayerVector::StateSet stateSet = LayerVector::StateSet::Invalid;
    LayerVector layersSortedByZ;
    DefaultKeyedVector< wp<IBinder>, DisplayDeviceState> displays;

    bool colorMatrixChanged = true;
    mat4 colorMatrix;

    void traverseInZOrder(const LayerVector::Visitor& visitor) const;
    void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
複製代碼

這個 State 類其實很是有說頭,只不過他們咱們本文的核心相關的就是裏面的 displays 成員,他是一個 <DefaultKeyedVector> 類型(Android 自定義的一個類型,與 std::map 相似),key-value 就是咱們前面都有提到的 DisplayTokenDisplayDeviceState

mCurrentStatemDrawingState 側重點不同:

  • mCurrentState 側重於 「變」mCurrentState 表明的是當前系統最新的狀態, 任什麼時候刻發生的各類改變都會被記錄在 mCurrentState
  • mDrawingState 側重於 「定」mDrawingState 表明的是本次合成時的狀態, SurfaceFlinger 在開始合成以前須要肯定本次合成的狀態,所以每次開始合成以前,SurfaceFlinger 都會經過 SurfaceFlinger::commitTransaction() 將記錄了當前最新的狀態的 mCurrentStatemDrawingState 作同步

原理分析

前面鋪墊了這麼長,終於來到了本文的中心內容了:

建立 VirtualDisplay

無論是 Java 代碼的 SurfaceControl.createVirtualDisplay() 仍是 C++ 代碼的 SurfaceComposerClient::createDisplay(),建立 VirtualDisplay 最終都會走到 SurfaceFlinger 的 createDisplay()

sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName,
         bool secure)
 {
     sp<BBinder> token = new DisplayToken(this);
  
     Mutex::Autolock _l(mStateLock);
     // Display ID is assigned when virtual display is allocated by HWC.
     DisplayDeviceState state;
     state.isSecure = secure;
     state.displayName = displayName;
     mCurrentState.displays.add(token, state);
     mInterceptor->saveDisplayCreation(state);
     return token;
 }
複製代碼

這個函數最重要的就是生成一個該 VirtualDisplay 的 DisplayDeviceState 和一個 DisplayToken,而且將這個 DisplayDeviceState 增長到 mCurrentState

須要注意的是,此時 Virtual Display 其實尚未被真正地建立,這裏只是經過修改 mCurrentState 記錄一下狀態的改變,真正的建立流程在後面。

state to transaction

回過頭看一下前面核心接口部分提到的 SurfaceComposerClient::Transaction::apply()

status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {
    ......
    sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
                            mDesiredPresentTime,
                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
                            listenerCallbacks);
複製代碼

這個函數最終會將 DisplayState 裏面的 DisplayTokenDisplayState 等內容發經過 SurfaceFlinger::setTransactionState() 傳遞給 SurfaceFlinger 端,而後通過以下調用之後:

SurfaceFlinger::setTransactionState()
  \_ SurfaceFlinger::applyTransactionState()
       \_  SurfaceFlinger::setDisplayStateLocked()
複製代碼

SurfaceFlinger::setDisplayStateLocked 中:

uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
    const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
    if (index < 0) return 0;

    uint32_t flags = 0;
    DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);

    const uint32_t what = s.what;
    if (what & DisplayState::eSurfaceChanged) {
        if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
            state.surface = s.surface;
            flags |= eDisplayTransactionNeeded;
        }
    }
複製代碼

DisplayState 中的 Surface (即 App 端建立的 BufferProducer) 傳遞給 DisplayDeviceState,同時將 eSurfaceChanged(回想一下前面的內容,surfacewhat 都是在 SurfaceComposerClient::Transaction::setDisplaySurface() 設置的) 轉換爲 eDisplayTransactionNeeded這一下,不只完成了 DisplayState 的內容傳遞到 DisplayDeviceState,還完成了 state 轉爲 Transaction 這一偉大壯舉,SurfaceFlinger 終於瞭解到了 App 側狀態的變更

而後回到 SurfaceFlinger::applyTransactionState() 將前面的 eDisplayTransactionNeeded 這個事務經過 SurfaceFlinger::setTransactionFlags() 保存起來,等待被處理。

SurfaceFlinger 處理事務

前面的 eDisplayTransactionNeeded 這個事務將會在下一個 SurfaceFlinger 的合成流程中,通過以下的函數調用:

SurfaceFlinger::handleMessageTransaction()
 \_ SurfaceFlinger::handleTransacion()
     \_ SurfaceFlinger::handleTransactionLocked()
複製代碼

最終在 processDisplayChangesLocked() 中被處理。

首先你們思考一個問題:

❔ SurfaceFlinger 怎麼知道在上個 VSYNC 中新增或者移除了 Display 呢?

答案就是前面提到的 mDrawingStatemCurrentStatemCurrentState 表明的是最新的狀態,mDrawingState 表明的是上一次合成的狀態(相對本次合成來講,在未 commitTransaction() 以前),所以假設:

  1. mCurrentState 中的 DisplayDeviceState 中有可是在 mDrawingState 中沒有,那麼就說明在上一個 VSYNC 中新增了 Display
  2. mDrawingState 中的 DisplayDeviceState 中有可是在 mCurrentState 中沒有,那麼就說明在上一個 VSYNC 中有 Display 被移除了

瞭解了這個之後咱們就能夠很簡單地判斷 Display 的變更了,本文的分析側重於新增 Display:

void SurfaceFlinger::processDisplayChangesLocked() {
    ......
    // find displays that were added
    // (ie: in current state but not in drawing state)
    for (size_t i = 0; i < cc; i++) {
        if (draw.indexOfKey(curr.keyAt(i)) < 0) {
            const DisplayDeviceState& state(curr[i]);

            sp<compositionengine::DisplaySurface> dispSurface;
            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferProducer> bqProducer;
            sp<IGraphicBufferConsumer> bqConsumer;
            getFactory().createBufferQueue(&bqProducer, &bqConsumer, false);

            std::optional<DisplayId> displayId;
            if (state.isVirtual()) {
                if (state.surface != nullptr) {
                    ......
                    // 給 VirtualDisplay 建立其 DisplaySurface —— VirtualDisplaySurface
                    sp<VirtualDisplaySurface> vds =
                            new VirtualDisplaySurface(getHwComposer(),
                                                      displayId, state.surface,
                                                      bqProducer, bqConsumer,
                                                      state.displayName);
                    dispSurface = vds;
                    producer = vds;
                }
            } else {
                displayId = state.displayId;
                LOG_ALWAYS_FATAL_IF(!displayId);
                // 給 主顯/外顯 建立其 DisplaySurface —— FrameBufferSurface
                dispSurface =
                    new FramebufferSurface(getHwComposer(), *displayId, bqConsumer);
                producer = bqProducer;
            }

            const wp<IBinder>& displayToken = curr.keyAt(i);
            if (dispSurface != nullptr) {
                // 真正建立 DisplayDevice 的地方,而且加入到 mDisplays
                mDisplays.emplace(displayToken,
                                  setupNewDisplayDeviceInternal(displayToken,
                                                                displayId, state,
                                                                dispSurface, producer));
                if (!state.isVirtual()) {
                    LOG_ALWAYS_FATAL_IF(!displayId);
                    dispatchDisplayHotplugEvent(displayId->value, true);
                }
            }
        }
    }
複製代碼

新增 Display 內容這部份內容比較多,分爲兩部分說明(說明:剩下的內容會着重於代碼流程以及數據流轉,涉及的衆多類以及其子類會新開一篇文章詳細說明。同時下面的內容也會涉及到 CompositionEngine 這一部分的內容,也會先粗略帶過,會單開新的文章單獨說明):

建立 DisplaySurface

前面提到,Android 支持多種 Display 類型,而每個 Display 都會有一個關聯的 Buffer,這個 Buffer 使用 DisplaySurface 這個類進行描述。不一樣類型的 Display 採用的 DisplaySurface 也不盡相同:主顯和外顯採用的是 FrameBufferSurface,而虛顯採用的是 VirtualDisplaySurface

VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc,
                                             const std::optional<DisplayId>& displayId,
                                             const sp<IGraphicBufferProducer>& sink,
                                             const sp<IGraphicBufferProducer>& bqProducer,
                                             const sp<IGraphicBufferConsumer>& bqConsumer,
                                             const std::string& name)
         ......
{
    mSource[SOURCE_SINK] = sink;
    mSource[SOURCE_SCRATCH] = bqProducer;
複製代碼

App 側傳過來的 BufferProducer 被保存爲 VirtualDisplaySurface 裏面的 mSource[SOURCE_SINK],這一點很重要,後文會用到。

建立 DisplayDevice

而後利用前面建立的 VirtualDisplaySurface,調用 setupNewDisplayDeviceInternal()

sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
        const wp<IBinder>& displayToken, const std::optional<DisplayId>& displayId,
        const DisplayDeviceState& state, const sp<compositionengine::DisplaySurface>& dispSurface,
        const sp<IGraphicBufferProducer>& producer) {
    ......

    auto nativeWindowSurface = getFactory().createNativeWindowSurface(producer);
    auto nativeWindow = nativeWindowSurface->getNativeWindow();
    creationArgs.nativeWindow = nativeWindow;
    
    ......

    sp<DisplayDevice> display = getFactory().createDisplayDevice(std::move(creationArgs));

    .......

    return display;
}
複製代碼

首先 setupNewDisplayDeviceInternal() 這個函數的 displaySurfaceproducer 這兩個參數都是前面建立的 VirtualDisplaySurface

接着利用前面建立的 VirtualDisplaySurface,使用 createNativeWindowSurface() 建立一個 native window。這裏簡單說明一下 native window 這個概念:

咱們知道,OpenGL ES 是一個跨平臺的圖形 API,可是即使是跨平臺,最終也是須要在具體的平臺上落地的,落地就須要在特定的平臺系統上「本地化」——把跨平臺的 OpenGL ES 跟具體平臺中的窗口系統創建起關聯,這樣才能保證正常工做,而爲 OenGL ES 提供本地窗口(即 native window)的就是 EGL,具體到 Android 裏,native window 其實就是指 Surface 這個類,在 frameworks/native/libs/gui/Surface.cpp 中定義。

而後看一下 native window 是怎麼建立的:

std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
        const sp<IGraphicBufferProducer>& producer) {
    class NativeWindowSurface final : public surfaceflinger::NativeWindowSurface {
    public:
        explicit NativeWindowSurface(const sp<IGraphicBufferProducer>& producer)
              : mSurface(new Surface(producer, /* controlledByApp */ false)) {}

        ~NativeWindowSurface() override = default;

        sp<ANativeWindow> getNativeWindow() const override { return mSurface; }

        void preallocateBuffers() override { mSurface->allocateBuffers(); }

    private:
        sp<Surface> mSurface;
    };

    return std::make_unique<NativeWindowSurface>(producer);
}
複製代碼

再看一下 Surface 的構造函數:

Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
      : mGraphicBufferProducer(bufferProducer),
    ......
複製代碼

從這個構造函數能夠很清楚地看到,建立出來的 native window,即 Surface,是將前面建立的 VirtualDisplaySurfacemGraphicBufferProducer 賦值的。請記住這一點,後面的數據流傳輸會用到。

而後就使用 createDisplayDevice() 建立一個 DisplayDeivce 而且添加到 mDisplays 中,VirtualDisplay 纔算真正建立完畢。

數據流傳輸

而後一切準備就緒之後,咱們終於來到最終的數據流傳輸。

每次合成的時候,SurfaceFlinger 對每一個 DisplayDevice 依次調用 doDisplayComposition()。在 VirtualDisplay 的 doDisplayComposition() 中,會調用 dequeueBuffer() 給接下來的合成(目前看 VirtualDisplay 都是 GPU 合成)申請 Buffer,這個 dequeueBuffer() 的調用流程十分值得說道說道:

回想一下前文咱們提到,setupNewDeviceInternal() 中的 createNativeWindow(),將 VirtualDisplaySurface 爲其成員 mGraphicBufferProducer 賦值,而在 SurfaceFlinger::dequeueBuffer() 中:

status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight,
                                                            reqFormat, reqUsage, &mBufferAge,
                                                            enableFrameTimestamps ? &frameTimestamps
                                                                                  : nullptr);
複製代碼

會去調用 mGraphicBufferProducer->dequeueBuffer(), 於是會轉而 VirtualDisplaySurface::dequeueBuffer()

status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, uint32_t w, uint32_t h,
                                              PixelFormat format, uint64_t usage,
                                              uint64_t* outBufferAge,
                                              FrameEventHistoryDelta* outTimestamps) {
    if (!mDisplayId) {
        return mSource[SOURCE_SINK]->dequeueBuffer(pslot,fence, w, h, format, usage,
                                                   outBufferAge, outTimestamps);
    }
    ......
複製代碼

回想一下前面的內容,對於 VirtualDisplay 來講,displayId 爲空,於是會直接調用 mSource[SOURCE_SINK]dequeueBuffer(),而咱們前面提到,mSource[SOURCE_SINK],就是 App 端傳來的 BufferProducer。

所以,最終整個 dequeueBuffer() 的調用流程以下:

RenderSurface::dequeueBuffer()
 \_ Surface::hook_dequeueBuffer()
     \_ Surface::dequeueBuffer()
         \_ VirtualDisplaySurface::dequeueBuffer()
             \_ 在這裏調用了 Client 端的 BufferProducer 的 dequeueBuffer()
複製代碼

通過一系列的 dequeueBuffer() 調用,SurfaceFlinger 最終拿到了 App 側的 BufferQueue 申請到的 Buffer,給錄屏 App 進行一次獨立的合成,並將合成的內容渲染到從 App 側拿到的 Buffer。是的,你沒有看錯,在這個場景裏,SurfaceFlinger 是內容的生產者,錄屏 App 纔是內容的消費者。最後,SurfaceFlinger 合成再經過 queueBuffer() 將渲染完的 Buffer 還給錄屏 App:

void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
                                          const Region& inDirtyRegion) {
    ......
    if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;

    // swap buffers (presentation)
    display->getRenderSurface()->queueBuffer(std::move(readyFence));
複製代碼

完整的調用流程跟 dequeueBuffer() 是徹底一致,再也不贅述。

最後,App 經過 onFrameAvailable() 獲得新 Buffer 的通知,經過 acquireBuffer((),在這裏拿到合成完的 Buffer(即當前屏幕的內容),就能夠對該 Buffer 而後就能夠開始進行各類處理(例如編解碼等)了。至此,整個數據傳輸的完整流程就說明完畢了。

總結

一句話總結錄屏的原理就是:

錄屏軟件經過建立一個 VirtualDisplay,而後每次 SurfaceFlinger 在作合成的時候,會對 VirtualDisplay 作一次獨立的合成,並將合成完的結果渲染到錄屏軟件傳遞過來的 Buffer。而錄屏軟件在拿到裝有當前畫面的 Buffer 之後,就能夠對 Buffer 進行進一步的處理如去作編解碼等,從而達到錄屏的目的。

而:

  1. App 側的改動,如新建的 VirtualDisplay 如何被 SurfaceFlinger 知曉
  2. 屏幕的內容是如何從 SurfaceFlinger 傳遞到錄屏 App

而這兩點,均可以用下面的這張圖來總結:

小插曲

以前在分析 DisplayState 的內容是怎麼傳遞給 DisplayDeviceState 的時候卡了好久,緣由是我執拗地認爲 SurfaceFlinger::setTransactionState() 只有 Display 在初始化的時候纔會調用,而且自信地加上了以下的 debug log:

結果我就被滿屏的 simowce: I don;t believe this'll print twice or more 啪啪打臉了:

尾巴

有讀者問過我爲何你寫東西寫得那麼慢?其實答案很是簡單,由於我寫的東西都是我不會且感興趣的,所以我都是邊學邊寫,而且由於我的有一種小小的偏執,就是一個東西若是沒弄懂就必須弄懂,於是就寫得很慢很慢。可是請你們放心,你們可以看到的內容都是我再三確認沒問題纔會發表的,質量絕對是有保證的。但願有一天,我可以在某個領域,自豪地說出那四個字:

以我爲準。

最後,你們若是以爲這篇文章寫得還不錯或者對你有幫助的話,麻煩點贊,轉載,分享到你的朋友圈或者相關的技術羣。謝謝你們了。

相關文章
相關標籤/搜索