display函数怎么使用_细极思恐!你有没有想过,录屏软件是怎么获取到屏幕内容的?...

8da722debd5cc24ed3add003d438d0d6.png
作者:simowce

前言

前段时间 Android R 发布了 Beta 版本,同时带来原生用户心心念念的功能——录屏,虽然这个功能在别的 Android 定制 ROM,像 MIUI,在好几年前已经就有了。是录屏这个功能是很难实现吗?为什么谷歌迟迟不肯在 Android 上这个功能呢?

再者,目前十分火爆的手机直播,大概可以分为两种形式:一种是让观众看到手机摄像头拍到的内容;另一种是让观众看到手机屏幕的内容。而后者,其实可以理解为另外一种形式的“录屏”。

那么,“录屏”在我们日常生活中这么常见的功能,你是否思考过,录屏背后的原理是什么?录屏软件又是怎么获取到屏幕的画面内容的呢?

阅读完本文,你可以了解到:

1.在 App 渲染合成中的状态与事务(State and Transaction)
2.录屏背后的功臣——Virtual Display 的核心接口以及 SurfaceFlinger 是如何发现,处理 VirtualDisplay
3.录屏的原理以及完整的数据流传输

如果你对这些内容感兴趣,那就接着看下去吧。如果对这些冗长的分析感到头疼,想要直接看到结论,可以直接放到最后面的总结。那我们开始吧。

c5038aa0cdcc71004e46dff94015d361.png

VirtualDisplay 简介

在目前的 Android 中,支持多种屏幕(Display,后文提到的 Display 都是指如下的各种屏幕)类型:

  • 内置的主屏幕
  • 通过 HDMI 连接的外接屏幕
  • 虚拟屏幕(Virtual Display)

前两种都是有具体的物理屏幕设备的,而与之相反的 Virtual Display 则没有,是由 SurfaceFlinger 模拟出来的,一大作用就是给前面反复提到的“录屏”提供基础设施。

核心接口

前面提到录屏背后用到的都是 VirtualDisplay,这里分别点一下 C++ 和 Java 中与 VirtualDisplay 相关的核心接口:

C++

在 Android 中有一个 screenrecord 的命令,这个命令是用纯 C++ 写的,源码路径在:frameworks/av/cmds/screenrecord/,通过这份谷歌官方的源码我们可以一窥 native 层实现录屏的原理(其实 Android 很早之前就支持录屏了哈哈)。其中的核心代码:

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()

c893111b457b3d981a6ccae9347ac3db.png

实现非常简单,通过 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 的 IGraphicBufferProducer 和 IGraphicBufferConsumer)关联起来。注意这里的 DisplayState::eSurfaceChanged,会是后面一系列流程重要的标志位。

  1. SurfaceComposerClient::Transaction::apply()

这个函数也非常重要,App 侧的改变都需要这个函数通知给 SurfaceFlinger 侧。

在后文会对三个接口做深入的分析。

79ccf83aaad1a5d236a0013a4d9d8cbb.png

Java

在 Android Framework 中有一个类 OverlayDisplayAdapter,这个类是方便 Framework 开发者创建模拟辅助显示设备,同样也有 C++ 提到的三个核心接口。事实上,Java 端的这些接口其实都是对做了一些封装,最终通过 JNI 调用到 native 层,最终的实现都是在 SurfaceFlinger。

状态与事务

状态

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::optional。std::optional 是 C++ 17 新引入的新特性,作用是方便表示或者处理一个变量“可能为空”的状态,如果在以前,我们会选择使用类似 NULL,null 或者 -1 这种特殊值来标记,但是现在,std::optional 给出了一种更加方便的方案,这里不做过多的语法描述。

在 DisplayDeviceState 中的 isVirtual() 就是用来判断该 DisplayDeviceState 对应的 Display 是否为 VirtualDisplay,而判断的依据就是 displayId.has_value(), 而对于 Virtual Display 来说,是不会对其 displayId 进行赋值的,而主显和外显则会赋值,因而 !displayId.has_value() 为 true,从而可以判断出 Display 是否为 VirtualDisplay。

DisplayToken

上面提到的 DisplayState 和 DisplayDeiveState 都是需要跟具体 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 计算原理 提到了的 mCurrentState 和 mDrawingState,类型就是 State。

State 是 SurfaceFlinger 这个类里面的一个内部类:

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 就是我们前面都有提到的 DisplayToken 和 DisplayDeviceState。

mCurrentState 和 mDrawingState 侧重点不一样:

  • mCurrentState 侧重于 “变”mCurrentState 代表的是当前系统最新的状态, 任何时刻发生的各种改变都会被记录在 mCurrentState 中
  • mDrawingState 侧重于 “定”mDrawingState 代表的是本次合成时的状态, SurfaceFlinger 在开始合成之前需要确定本次合成的状态,因此每次开始合成之前,SurfaceFlinger 都会通过 SurfaceFlinger::commitTransaction() 将记录了当前最新的状态的 mCurrentState 与 mDrawingState 做同步

dca4c312ea85f1dfe2a9251ee0e2e0c9.png

原理分析

前面铺垫了这么长,终于来到了本文的中心内容了:

创建 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 里面的 DisplayToken 和 DisplayState 等内容发通过 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(回想一下前面的内容,surface 和 what 都是在 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 呢?

答案就是前面提到的 mDrawingState 和 mCurrentState。mCurrentState 代表的是最新的状态,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() 这个函数的 displaySurface 和 producer 这两个参数都是前面创建的 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,是将前面创建的 VirtualDisplaySurface 给 mGraphicBufferProducer 赋值的。请记住这一点,后面的数据流传输会用到。

然后就使用 createDisplayDevice() 创建一个 DisplayDeivce 并且添加到 mDisplays 中,VirtualDisplay 才算真正创建完毕。

6c85bea5bd0963dc72e03410688264db.png

数据流传输

然后一切准备就绪以后,我们终于来到最终的数据流传输。

每次合成的时候,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

而这两点,都可以用下面的这张图来总结:

c9c27373a2db1d90af5763dbfc7c74da.png

小插曲

之前在分析 DisplayState 的内容是怎么传递给 DisplayDeviceState 的时候卡了很久,原因是我固执地认为 SurfaceFlinger::setTransactionState() 只有 Display 在初始化的时候才会调用,并且自信地加上了如下的 debug log:

c5a36b696f26f683ea201900205f3751.png

结果我就被满屏的 simowce: I don;t believe this'll print twice or more 啪啪打脸了:

3de220ea754b9ab73c8081100bf93b33.png

尾巴

有读者问过我为什么你写东西写得那么慢?其实答案非常简单,因为我写的东西都是我不会且感兴趣的,因此我都是边学边写,并且因为个人有一种小小的偏执,就是一个东西如果没弄懂就必须弄懂,因而就写得很慢很慢。但是请大家放心,大家能够看到的内容都是我再三确认没问题才会发表的,质量绝对是有保证的。希望有一天,我能够在某个领域,自豪地说出那四个字:

以我为准。

如果需要我收录整理的Android学习PDF+架构视频+面试文档+源码笔记高级架构技术进阶脑图、Android开发面试专题资料,高级进阶架构资料的话,可以私信或评论我,免费获取

Android学习PDF+架构视频+面试文档+源码笔记​shimo.im

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

f21a77f1bc191136b6b8743bbd3e3f1c.png

d82659fc5cd6413d2eb15d238d9d2a65.png

11a21fab8f7198ed6331a3a9b8e6d396.png
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值