GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系

时间:2022-08-01 03:52:30

文章都是通过阅读源码分析出来的,还在不断完善与改进中,其中难免有些地方理解得不对,欢迎大家批评指正。
转载请注明:From LXS. http://blog.csdn.net/uiop78uiop78/

GUI系统之SurfaceFlinger章节目录:
blog.csdn.net/uiop78uiop78/article/details/8954508





1.1.1 应用程序与BufferQueue的关系

接着上一小节未解决完的问题继续讲解。

现在我们已经明白了应用程序利用SurfaceFlinger进行绘制工作的大致流程了,只不过在这个过程中直到最后才出现了BufferQueue。应用程序具体是如何借助BufferQueue来完成工作的呢?

仔细观察不难发现,当应用端通过ISurfaceComposerClient::createSurface()来发起创建Surface的请求时,SurfaceFlinger服务进程这边会创建一个Layer。既然Layer代表了一个画面图层,那么它肯定需要有存储图层数据的地方,因而我们选择从这里做为入口。

/*frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp*/

/*应用程序首先是要通过ISurfaceComposerClient来访问createSurface,这个接口实际上只是一个中介,它将应用的请求传送到SurfaceFlinger的消息队列中,而不是直接调用SurfaceFlinger来处理。这样做是有必要的,因为一个系统中需要SurfaceFlinger处理的来自各应用程序的消息是很多的,除非一些紧急情况,否则都应该排队等待*/

sp<ISurface>SurfaceFlinger::createSurface(ISurfaceComposerClient::surface_data_t* params,

constString8& name, const sp<Client>& client, DisplayID d,

uint32_tw, uint32_t h, PixelFormat format, uint32_t flags)

{

    sp<LayerBaseClient>layer;

    sp<ISurface>surfaceHandle;

    …

    sp<Layer>normalLayer;

    switch (flags &eFXSurfaceMask) { //Layer类型

        case eFXSurfaceNormal:

            normalLayer = createNormalSurface(client, d, w, h, flags, format);

            layer =normalLayer;

            break;

        case eFXSurfaceBlur://4.1系统中将Blur与Dim类型当成一种

        case eFXSurfaceDim:

            layer = createDimSurface(client, d, w, h, flags);

            break;

        case eFXSurfaceScreenshot:

            layer = createScreenshotSurface(client, d, w, h, flags);

            break;

    }

    if (layer != 0) {…      

        surfaceHandle = layer->getSurface();

        …

    }

    return surfaceHandle;

}

可以看到,最后返回给应用程序的ISurface对应的变量是surfaceHandle,由layer通过getSurface()产生。从enum值定义来看,当前系统中有多达十几种Layer类型,只不过多数还没有真正实现,目前能用的只有四个,即eFXSurfaceNormal、eFXSurfaceBlur、eFXSurfaceDim、eFXSurfaceScreenshot。第一种就是通常情况下的图层;第二和第三种在当前系统中都被以eFXSurfaceDim来实现,从注释上看,很可能是Blur类型的Layer比较耗资源,所以暂时用Dim来取代。相信在后续的Android版本中还会把它们再区分开来。

Layer和ISurface有什么联系?

GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系

图 11‑18 Layer类继承关系

 

/*frameworks/native/services/surfaceflinger/LayerBase.cpp*/

sp<ISurface> LayerBaseClient::getSurface()

{

    sp<ISurface> s;

    Mutex::Autolock _l(mLock);

   LOG_ALWAYS_FATAL_IF(mHasSurface, "LayerBaseClient::getSurface() hasalready been called");

    mHasSurface = true;

    s = createSurface(); //通过这个函数产生一个ISurface

    mClientSurfaceBinder= s->asBinder();

    return s;

}

这个函数只能被调用一次,由mHasSurface来控制。当被第二次调用时,就会发生assert错误。LayerBaseClient通过成员变量mClientSurfaceBinder来记录ISurface。一个系统中同时存在的Layer和Surface通常不会只有一个,那么ISurface是如何知道它所属的Layer的呢?

sp<ISurface> LayerBaseClient::createSurface()

{

    class BSurface : publicBnSurface, public LayerCleaner {

        virtualsp<ISurfaceTexture> getSurfaceTexture() const { return 0; }

    public:

        BSurface(constsp<SurfaceFlinger>& flinger, const sp<LayerBaseClient>&layer)

            :LayerCleaner(flinger, layer) { }

    };

    sp<ISurface> sur(newBSurface(mFlinger, this));

    return sur;

}

和一般的写法不同,ISurface的本地实现BSurface是定义在函数中的。不过这不是问题的关键,关键问题是BSurface中的getSurfaceTexture居然直接返回了一个null(0),显然如果是这样的话程序就没法继续执行了。唯一的解释是应该有LayerBaseClient的子类重载实现了这一函数,来看下Layer中是不是这样的。

/*frameworks/native/services/surfaceflinger/Layer.cpp*/

sp<ISurface> Layer::createSurface()

{

    class BSurface : publicBnSurface, public LayerCleaner {

        wp<const Layer>mOwner;

        virtualsp<ISurfaceTexture> getSurfaceTexture() const {

           sp<ISurfaceTexture> res;

            sp<constLayer> that( mOwner.promote() );

            if (that != NULL){

                res =that->mSurfaceTexture->getBufferQueue();

            }

            return res;

        }

    public:

        BSurface(constsp<SurfaceFlinger>& flinger, const sp<Layer>& layer)

            : LayerCleaner(flinger,layer), mOwner(layer) { }//mOwner在构造函数中以Layer赋值

    };

    sp<ISurface> sur(newBSurface(mFlinger, this));

    return sur;

}

看来我们猜测的是对的,Layer的确重载了createSurface。而且这里的getSurfaceTexture就不是pseudo的了。函数的最后生成了一个BSurface,注意看下它的构造参数中传入了this指针,也就是Layer对象自身。这个指针是后期ISurface与它通信的关键。同时作为入参的还有mFlinger,这样ISurface也可以访问到SurfaceFlinger了。因为这几个类都运行于同一个进程空间中,可以看到它们都直接是内存地址的传递,不需要IPC通信。

当应用程序通过ISurfaceComposerClient::createSurface()得到一个ISurface后,它会接着使用ISurface::getSurfaceTexture()来取得可用的texture(具体是由Surface在构造时获取,然后再通过Surface::init->setISurfaceTexture来将ISurfaceTexture赋值给SurfaceTextureClient::mSurfaceTexture),这个ISurfaceTexture是应用程序中的opengl本地窗口SurfaceTextureClient实现ANativeWindow规定的“协议”的基础)。

在getSurfaceTexture中,mOwner是一个指向Layer对象的弱指针,that->mSurfaceTexture指的是Layer中的SurfaceTexture类成员变量,所以函数最终是通过SurfaceTexture::getBufferQueue()来获得ISurfaceTexture。更具体地过程是,当Layer第一次被引用时,在onFirstRef()中会对mSurfaceTexture赋值。因为ISurface(即BSurface)持有这个Layer对象(mOwner),所以当应用程序申请getSurfaceTexture时,它才能间接地向Layer要求取得ISurfaceTexture。我们前面说过,在binder server端,这个接口的实现类就是BufferQueue,如下所示:

/*frameworks/native/libs/gui/SurfaceTexture.cpp*/

sp<BufferQueue> SurfaceTexture::getBufferQueue() const {

    Mutex::Autolocklock(mMutex);

    return mBufferQueue;

}

函数直接返回了mBufferQueue,因为这个成员变量在SurfaceTexture构造时就已经初始化过了,它指向一个BufferQueue对象。大家一定要记住,ISurfaceTexture的server端实现是BufferQueue,由于命名上的差异,这点很容易搞错。

这样应用程序与BufferQueue的关系就比较明朗了。虽然中间经历了多次跨进程通信,但对于应用程序来说最终只使用到了BufferQueue(通过ISurfaceTexture)。从本小节的内容中,我们也可以从侧面证明如下几个关键点:

(1) 应用程序可以调用createSurface来建立多个Layer,它们是一对多的关系。理由就是createSurface中没有任何机制来限制应用程序的多次调用,相反,它会把一个应用程序多次申请而产生的Layer统一管理,如下:

sp<ISurface> SurfaceFlinger::createSurface(…constsp<Client>& client)

{

    sp<LayerBaseClient>layer;

    … /*省略的这部分是生成layer的过程,前面已经分析过了*/

    if (layer != 0) {…

        ssize_t  token = addClientLayer(client,layer);//将client与layer记录起来

        surfaceHandle =layer->getSurface();

        if (surfaceHandle !=0) {…

            if (normalLayer !=0) {//只对normal layer生效

               Mutex::Autolock _l(mStateLock);

                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);

            }

        }…

}

为应用程序申请的layer,一方面需要告知SurfaceFlinger,另一方面也要记录到各Client内部中,这两个步骤是由addClientLayer()分别调用Client::attachLayer()和SurfaceFlinger::addLayer_l()来完成的。对于SurfaceFlinger,它需要对系统中当前所有的Layer进行Z-order排序,以决定用户所能看到的“画面”是什么样的。对于Client,它则利用内部的mLayers成员变量来一一记录新增(attachLayer)和移除(detachLayer)的图层。

 

(2) 每个Layer对应一个BufferQueue,换句话说,一个应用程序可能对应多个BufferQueue。Layer没有直接持有BufferQueue,而是由其内部的mSurfaceTexture来管理。

 

我们以下面这个关系图来结束本小节的学习:

GUI系统之SurfaceFlinger(8)应用程序与BufferQueue的关系

图 11‑19 应用程序与BufferQueue的对应关系