Android12 显示框架之getSurface

目录:Android显示终极宝典

在上篇文章中,我们讲到了应用通过createSurface()在surfaceflinger内生成了一个Layer,并且获取到了该Layer的Handle且将其和其他信息保存到了SurfaceControl。应用拿到了这个SurfaceControl,那么接下来就要创建应用端的surface了。完成这个任务的接口就是getSurface()。

SurfaceControl::getSurface()

cpp 复制代码
//frameworks/native/libs/gui/SurfaceControl.cpp
sp<Surface> SurfaceControl::getSurface()
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == nullptr) {
        return generateSurfaceLocked();
    }
    return mSurfaceData;
}

sp<Surface> SurfaceControl::generateSurfaceLocked()
{
    uint32_t ignore;
    auto flags = mCreateFlags & (ISurfaceComposerClient::eCursorWindow |
                                 ISurfaceComposerClient::eOpaque);
    mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat,
                                       flags, mHandle, {}, &ignore);
    mBbq = sp<BLASTBufferQueue>::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat);

    // This surface is always consumed by SurfaceFlinger, so the
    // producerControlledByApp value doesn't matter; using false.
    mSurfaceData = mBbq->getSurface(true);

    return mSurfaceData;
}

我们在这个函数里发现两个点,这是Android12与之前版本的不同之处,一个是这里再次调用并创建一个SurfaceControl,另一个是创建一个BLASTBufferQueue。个人感觉这个设计应该还是一个过渡性的内容,因为里面的内容多多少少感觉有些冗余性。

下面逐一看看generateSurfaceLocked()内部要做的事情:

createSurface()

这里不再赘述了,上一篇文章已经讲解过了。这里生成的SurfaceControl保存在了当前SurfaceControl的mBbqChild变量中。值得注意的是,这里创建Layer时传入的宽和高都为0。

创建BLASTBufferQueue

这是Android12新加入的内容,其实就是对BufferQueue的一个封装。之前应用的BufferQueue都是在surfaceflinger内部,现在Google把它移到了应用进程内自己管理。这个可能是想参考Wayland的设计吧。

言归正传,来看看BLASTBufferQueue的构造过程:

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
                                   int width, int height, int32_t format)
      : mSurfaceControl(surface),
        mSize(width, height),
        mRequestedSize(mSize),
        mFormat(format),
        mNextTransaction(nullptr) {
    createBufferQueue(&mProducer, &mConsumer);
    // since the adapter is in the client process, set dequeue timeout
    // explicitly so that dequeueBuffer will block
    mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());

    // safe default, most producers are expected to override this
    mProducer->setMaxDequeuedBufferCount(2);
    mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
                                                      GraphicBuffer::USAGE_HW_COMPOSER |
                                                              GraphicBuffer::USAGE_HW_TEXTURE,
                                                      1, false);
    static int32_t id = 0;
    mName = name + "#" + std::to_string(id);
    auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
    mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(id);
    id++;
    mBufferItemConsumer->setName(String8(consumerName.c_str()));
    mBufferItemConsumer->setFrameAvailableListener(this);
    mBufferItemConsumer->setBufferFreedListener(this);
    mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
    mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
    mBufferItemConsumer->setBlastBufferQueue(this);

    ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
    mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);

    mTransformHint = mSurfaceControl->getTransformHint();
    mBufferItemConsumer->setTransformHint(mTransformHint);
    SurfaceComposerClient::Transaction()
            .setFlags(surface, layer_state_t::eEnableBackpressure,
                      layer_state_t::eEnableBackpressure)
            .setApplyToken(mApplyToken)
            .apply();
    mNumAcquired = 0;
    mNumFrameAvailable = 0;
    BQA_LOGV("BLASTBufferQueue created width=%d height=%d format=%d mTransformHint=%d", width,
             height, format, mTransformHint);
}

构造函数还是有点东西的,但是不多。我们逐一拆解:

createBufferQueue()

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                                         sp<IGraphicBufferConsumer>* outConsumer) {
    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");

    sp<BufferQueueCore> core(new BufferQueueCore());
    LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");

    sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
    LOG_ALWAYS_FATAL_IF(producer == nullptr,
                        "BLASTBufferQueue: failed to create BBQBufferQueueProducer");

    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
    consumer->setAllowExtraAcquire(true);
    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
                        "BLASTBufferQueue: failed to create BufferQueueConsumer");

    *outProducer = producer;
    *outConsumer = consumer;
}

很简单,

  • 创建了一个BufferQueue,即BufferQueueCore。
  • 基于BufferQueue创建了一个生产者,即BBQBufferQueueProducer。
  • 基于BufferQueue创建了一个消费者,即BufferQueueConsumer。

BLASTBufferItemConsumer

cpp 复制代码
//frameworks/native/include/gui/BLASTBufferQueue.h
BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
						int bufferCount, bool controlledByApp)
	  : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
		mCurrentlyConnected(false),
		mPreviouslyConnected(false),
		mBLASTBufferQueue(nullptr) {}

//frameworks/native/libs/gui/BufferItemConsumer.cpp
BufferItemConsumer::BufferItemConsumer(
        const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
        int bufferCount, bool controlledByApp) :
    ConsumerBase(consumer, controlledByApp)
{
    status_t err = mConsumer->setConsumerUsageBits(consumerUsage);
    LOG_ALWAYS_FATAL_IF(err != OK,
            "Failed to set consumer usage bits to %#" PRIx64, consumerUsage);
    if (bufferCount != DEFAULT_MAX_BUFFERS) {
        err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
        LOG_ALWAYS_FATAL_IF(err != OK,
                "Failed to set max acquired buffer count to %d", bufferCount);
    }
}

//frameworks/native/libs/gui/ConsumerBase.cpp
ConsumerBase::ConsumerBase(const sp<IGraphicBufferConsumer>& bufferQueue, bool controlledByApp) :
        mAbandoned(false),
        mConsumer(bufferQueue),
        mPrevFinalReleaseFence(Fence::NO_FENCE) {
    // Choose a name using the PID and a process-unique ID.
    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());

    // Note that we can't create an sp<...>(this) in a ctor that will not keep a
    // reference once the ctor ends, as that would cause the refcount of 'this'
    // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
    // that's what we create.
    wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
    sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);

    status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
    if (err != NO_ERROR) {
        CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
                strerror(-err), err);
    } else {
        mConsumer->setConsumerName(mName);
    }
}

可以看到三者之间的继承关系:BLASTBufferItemConsumer->BufferItemConsumer->ConsumerBase。在ConsumerBase构造函数内会创建一个ProxyConsumerListener,并且通过BufferQueueConsumer将其保存到BufferQueueCore内。

setFrameAvailableListener()

将BLASTBufferQueue本身设置到ConsumerBase的mFrameAvailableListener对象,当有新的帧到来时,它会被通知到。

setBufferFreedListener()

将BLASTBufferQueue本身设置到BufferItemConsumer的mBufferFreedListener对象,当有旧的buffer在被释放时,它会被通知到。

Transaction

SurfaceComposerClient::Transaction()设置Layer对应的属性到surfaceflinger,这里设置了layer_state_t和applyToken两种属性。下一篇文章将详细讲解Transaction的原理。

到此,BLASTBufferQueue创建完毕,接下来就是真正创建应用端surface的时候了。

BLASTBufferQueue::getSurface()

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
    std::unique_lock _lock{mMutex};
    sp<IBinder> scHandle = nullptr;
    if (includeSurfaceControlHandle && mSurfaceControl) {
        scHandle = mSurfaceControl->getHandle();
    }
    return new BBQSurface(mProducer, true, scHandle, this);
}

这里首先看mSurfaceControl->getHandle(),它的mSurfaceControl是指向当前SurfaceControl的子SurfaceControl的,所以用来获取子SurfaceControl的Handle。

cpp 复制代码
//frameworks/native/libs/gui/SurfaceControl.cpp
sp<IBinder> SurfaceControl::getHandle() const {
    if (mBbqChild != nullptr) {
        return mBbqChild->getHandle();
    }
    return getLayerStateHandle();
}

sp<IBinder> SurfaceControl::getLayerStateHandle() const
{
    return mHandle;
}

看getHandle()的实现很明显的看出,这个函数永远获取子SurfaceControl所指向的mHandle。

最后是new一个BBQSurface,它继承自Surface:

cpp 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
		   const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
	  : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}

这里用BLASTBufferQueue本身、它的BBQBufferQueueProducer、Layer的Handle构建出了一个BBQSurface。

简单的画个BLASTBufferQueue的生产者消费者模型则如下:

总结

通过本节内容,应用程序搭建完成了生产者消费者模型,获取到了Surface接口端,下面就可以生产buffer送显了。但是在这之前还要设置surface的各项属性,通过Transaction来达成目的,这个在下节讲解,这里提一嘴。

老规矩,还是通过框架图的形式总结下本节的内容,注意这里没有再去画出来surfaceflinger内部生成的内容了,因为上篇文章已经展示过了。

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui