你有没有想过,录屏软件是怎么获取到屏幕内容的?

欢迎你们关注个人微信公众号——“简静慢”,除了技术文章,我还会在里面分享一些平常的思考,欢迎一块儿交流。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 啪啪打脸了:

尾巴

有读者问过我为何你写东西写得那么慢?其实答案很是简单,由于我写的东西都是我不会且感兴趣的,所以我都是边学边写,而且由于我的有一种小小的偏执,就是一个东西若是没弄懂就必须弄懂,于是就写得很慢很慢。可是请你们放心,你们可以看到的内容都是我再三确认没问题才会发表的,质量绝对是有保证的。但愿有一天,我可以在某个领域,自豪地说出那四个字:

以我为准。

最后,你们若是以为这篇文章写得还不错或者对你有帮助的话,麻烦点赞,转载,分享到你的朋友圈或者相关的技术群。谢谢你们了。

相关文章
相关标签/搜索