Android GUI system's SurfaceFlinger (02) application end analysis 1 - get Surface

Link to the general outline of this series of articles: surface flinger series of articles of Android GUI system

Summary & description of key points in this chapter:

The mind map of this chapter is as above. This paper mainly introduces the demo of surf CE test program A kind of Step 2: obtain the client of SurfaceFlinger, then the SurfaceControl, and then the Surface.

Key source code description

This part of the code is a simplified version of the source code of the Surface test program in the previous chapter, which saves the most critical processes as follows:

#include <cutils/memory.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <android/native_window.h>

using namespace android;

int main(int argc, char** argv)
{
    //...
    //1 create the client of the surfacelinker
    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
    
    //2 get surface
    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);
    sp<Surface> surface = surfaceControl->getSurface();

    //Set the layer. The higher the layer value is, the higher the display layer is
    SurfaceComposerClient::openGlobalTransaction();
    surfaceControl->setLayer(100000);
    SurfaceComposerClient::closeGlobalTransaction();

    //3 get buffer - > lock buffer - > write buffer - > unlock and submit buffer 
    //The main focus here: apply for Buff and submit Buff
    ANativeWindow_Buffer outBuffer;
    surface->lock(&outBuffer, NULL);
    ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
    android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
    surface->unlockAndPost();
    //...
    
    return 0;
}

The main steps are:

  1. Obtain the client of the SurfaceFlinger (hereafter referred to as SF), obtain the SurfaceControl through the client of SF, and then obtain the Surface
  2. Set Layer value through SurfaceControl (ignored), obtain Buffer through Surface, lock Buffer and write Buffer
  3. Last commit Buffer

This chapter focuses on step 1 and step 2, obtaining the SF client, then obtaining the SurfaceControl, and then obtaining the Surface.

1 get SF client

We start with the following source code:

sp<SurfaceComposerClient> client = new SurfaceComposerClient();

Analyze the surfacecomposerclient with the following code:

SurfaceComposerClient::SurfaceComposerClient()
    : mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}

The main task is to initialize mStatus and mComposer, and pay attention to the following key onfirsref functions. The code is as follows:

void SurfaceComposerClient::onFirstRef() {
    //Get clients for SF service
    sp<ISurfaceComposer> sm(ComposerService::getComposerService());
    if (sm != 0) {
        //Obtained through the createConnection of SF service
        //A client object (type ISurfaceComposerClient)
        sp<ISurfaceComposerClient> conn = sm->createConnection();
        if (conn != 0) {
            mClient = conn;
            mStatus = NO_ERROR;
        }
    }
}

First, obtain the SF service. Access the createConnection method of the SF service to obtain the client (isurfacerecomposerclient type, which actually corresponds to an APP) object. The code is as follows:

sp<ISurfaceComposerClient> SurfaceFlinger::createConnection()
{
    sp<ISurfaceComposerClient> bclient;
    sp<Client> client(new Client(this));
    status_t err = client->initCheck();
    if (err == NO_ERROR) {
        bclient = client;
    }
    return bclient;
}

This is mainly to create a client and return it to the conn of the previous layer. (the analysis of Binder communication part is ignored in the whole analysis process. See the link of series articles for Binder communication part: The core mechanism of android system binder )At the end of this paper, a UML diagram of Binder communication architecture of this part is shown as follows:

2 get Surface

We first obtain the SF client, then the SurfaceControl, and then the Surface through SurfaceControl, so we first analyze the process of obtaining SurfaceControl, and then analyze the process of obtaining Surface. The key codes are as follows:

    sp<SurfaceControl> surfaceControl = client->createSurface(String8("resize"),
            160, 240, PIXEL_FORMAT_RGB_565, 0);
    sp<Surface> surface = surfaceControl->getSurface();

2.1 get SurfaceControl

Pay attention to the first sentence in the above code. The implementation code of createSurface is as follows:

sp<SurfaceControl> SurfaceComposerClient::createSurface(
        const String8& name,
        uint32_t w,
        uint32_t h,
        PixelFormat format,
        uint32_t flags)
{
    sp<SurfaceControl> sur;
    if (mStatus == NO_ERROR) {
        sp<IBinder> handle;
        sp<IGraphicBufferProducer> gbp;
        status_t err = mClient->createSurface(name, w, h, format, flags,
                &handle, &gbp);
        ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
        if (err == NO_ERROR) {
            sur = new SurfaceControl(this, handle, gbp);
        }
    }
    return sur;
}

The mClient->createSurface method here finally calls the createSurface of the Client class (which ignores the analysis of the Binder communication part. The Binder communication section is detailed in the series article link: The core mechanism of android system binder ), the relevant codes are as follows:

status_t Client::createSurface(
        const String8& name,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle,
        sp<IGraphicBufferProducer>* gbp)
{
    class MessageCreateLayer : public MessageBase {
        SurfaceFlinger* flinger;
        Client* client;
        sp<IBinder>* handle;
        sp<IGraphicBufferProducer>* gbp;
        status_t result;
        const String8& name;
        uint32_t w, h;
        PixelFormat format;
        uint32_t flags;
    public:
        MessageCreateLayer(SurfaceFlinger* flinger,
                const String8& name, Client* client,
                uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
                sp<IBinder>* handle,
                sp<IGraphicBufferProducer>* gbp)
            : flinger(flinger), client(client),
              handle(handle), gbp(gbp),
              name(name), w(w), h(h), format(format), flags(flags) {
        }
        status_t getResult() const { return result; }
        virtual bool handler() {
            //Create Layer with SF
            result = flinger->createLayer(name, client, w, h, format, flags,
                    handle, gbp);
            return true;
        }
    };

    sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(),
            name, this, w, h, format, flags, handle, gbp);
    mFlinger->postMessageSync(msg);
    return static_cast<MessageCreateLayer*>( msg.get() )->getResult();
}

Here is mainly to send messages through the handler Message mechanism. Finally, a Layer is created through SF. The code of createLayer is as follows:

status_t SurfaceFlinger::createLayer(
        const String8& name,
        const sp<Client>& client,
        uint32_t w, uint32_t h, PixelFormat format, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp)
{
    if (int32_t(w|h) < 0) {
        return BAD_VALUE;
    }
    status_t result = NO_ERROR;
    sp<Layer> layer;

    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createNormalLayer(client,
                    name, w, h, flags, format,
                    handle, gbp, &layer);
            break;
        case ISurfaceComposerClient::eFXSurfaceDim:
            result = createDimLayer(client,
                    name, w, h, flags,
                    handle, gbp, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }

    if (result == NO_ERROR) {
        addClientLayer(client, *handle, *gbp, layer);
        setTransactionFlags(eTransactionNeeded);
    }
    return result;
}

At the same time, when creating a Layer, there will be two branches: use createNormalLayer to create a general Layer or createDimLayer to create a DimLayer. Finally, the handle and gbp will be assigned. The two codes are as follows:

status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    // initialize the surfaces
    switch (format) {
    case PIXEL_FORMAT_TRANSPARENT:
    case PIXEL_FORMAT_TRANSLUCENT:
        format = PIXEL_FORMAT_RGBA_8888;
        break;
    case PIXEL_FORMAT_OPAQUE:
        format = PIXEL_FORMAT_RGBX_8888;
        break;
    }

    *outLayer = new Layer(this, client, name, w, h, flags);
    status_t err = (*outLayer)->setBuffers(w, h, format, flags);
    if (err == NO_ERROR) {
        *handle = (*outLayer)->getHandle();
        *gbp = (*outLayer)->getProducer();
    }

    return err;
}

status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    *outLayer = new LayerDim(this, client, name, w, h, flags);
    *handle = (*outLayer)->getHandle();
    *gbp = (*outLayer)->getProducer();
    return NO_ERROR;
}

Both have this Code:

    *handle = (*outLayer)->getHandle();
    *gbp = (*outLayer)->getProducer();

In other words, the handle and gbp (which will be analyzed in detail later) will be assigned values. Finally, these two values will be passed to the newly created SurfaceControl and returned. That is to say, the SurfaceControl of each Client (corresponding to APP) corresponds to a Layer. At the same time, the LayerDim in the above code also inherits the Layer, so what do you do to create the Layer? We need to analyze Layer in detail.

2.2 Layer analysis created

The constructor of Layer class is as follows:

Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags)
    :   contentDirty(false),
        //...
        mClientRef(client),
        mPotentialCursor(false)
{
    mCurrentCrop.makeInvalid();
    mFlinger->getRenderEngine().genTextures(1, &mTextureName);
    mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);

    uint32_t layerFlags = 0;
    if (flags & ISurfaceComposerClient::eHidden)
        layerFlags |= layer_state_t::eLayerHidden;
    if (flags & ISurfaceComposerClient::eOpaque)
        layerFlags |= layer_state_t::eLayerOpaque;

    if (flags & ISurfaceComposerClient::eNonPremultiplied)
        mPremultipliedAlpha = false;

    mName = name;

    mCurrentState.active.w = w;
    //...
    mCurrentState.requested = mCurrentState.active;

    // drawing state & current state are identical
    mDrawingState = mCurrentState;

    nsecs_t displayPeriod =
            flinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
    mFrameTracker.setDisplayRefreshPeriod(displayPeriod);
}

It can be seen that the above is mainly for the initialization of some variables. Let's ignore it for the moment, and then look at the key method onfirsref. The code is as follows:

void Layer::onFirstRef() {
    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
    sp<IGraphicBufferProducer> producer;
    sp<IGraphicBufferConsumer> consumer;
    BufferQueue::createBufferQueue(&producer, &consumer);
    mProducer = new MonitoredProducer(producer, mFlinger);
    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName);
    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
    mSurfaceFlingerConsumer->setContentsChangedListener(this);
    mSurfaceFlingerConsumer->setName(mName);

#ifdef TARGET_DISABLE_TRIPLE_BUFFERING
#warning "disabling triple buffering"
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(2);
#else
    mSurfaceFlingerConsumer->setDefaultMaxBufferCount(3);
#endif

    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
    updateTransformHint(hw);
}

2.2.1 createBufferQueue method

Here we focus on the createBufferQueue method of BufferQueue. The code is as follows:

void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
        sp<IGraphicBufferConsumer>* outConsumer,
        const sp<IGraphicBufferAlloc>& allocator) {
    sp<BufferQueueCore> core(new BufferQueueCore(allocator));
    sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core));
    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
    *outProducer = producer;
    *outConsumer = consumer;
}

As you can see, each Layer has a producer and consumer and points to the same BufferQueueCore. There is a key member variable in the BufferQueueCore: BufferQueueDefs::SlotsType mSlots; SlotsType type is an array of 64. That is to say, the producer and consumer finally point to the same core array mSlots (an array of 64 elements).

2.2.2 MonitoredProducer class analysis

The relationship between producer and SF in monitoredproducer (producer, mfringer) is that SF removes producer from mgraphicbufferproducer list (gbp chain list) during structure decomposition. The corresponding code is as follows:

//Constructor
MonitoredProducer::MonitoredProducer(const sp<IGraphicBufferProducer>& producer,
        const sp<SurfaceFlinger>& flinger) :
    mProducer(producer),
    mFlinger(flinger) {}
//Destructor
MonitoredProducer::~MonitoredProducer() {
    class MessageCleanUpList : public MessageBase {
    public:
        MessageCleanUpList(const sp<SurfaceFlinger>& flinger,
                const wp<IBinder>& producer)
            : mFlinger(flinger), mProducer(producer) {}
        virtual ~MessageCleanUpList() {}
        virtual bool handler() {
            Mutex::Autolock _l(mFlinger->mStateLock);
            mFlinger->mGraphicBufferProducerList.remove(mProducer);
            return true;
        }
    private:
        sp<SurfaceFlinger> mFlinger;
        wp<IBinder> mProducer;
    };

    mFlinger->postMessageAsync(new MessageCleanUpList(mFlinger, asBinder()));
}

2.3 obtaining Surface

Pay attention to the second sentence in the above code. The implementation code of surfacecontrol - > getsurface() is as follows:

sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        // This surface is always consumed by SurfaceFlinger, so the
        // producerControlledByApp value doesn't matter; using false.
        //The mGraphicBufferProducer here is the gbp passed in before
        mSurfaceData = new Surface(mGraphicBufferProducer, false);
    }
    return mSurfaceData;
}

Here, a new Surface is created and the gbp parameter is passed to the Surface. Finally, it returns.

2.4 summary

APP corresponds to a client, a SurfaceControl corresponds to a Layer, and gbp (BpGraphicBufferProducer) corresponds to mProducer (BnGraphicBufferProducer) in the Layer. They all comply with the same interface IGraphicBufferProducer. The relationship between related classes is as follows:

 

 

 

 

 

 

 

224 original articles published, 30 praised, 20000 visitors+
Private letter follow

Tags: Android

Posted on Fri, 13 Mar 2020 21:47:15 -0700 by miz_luvly@hotmail.com