10 Analyze SurfaceComposerClient submission transaction process

After using SurfaceComposerClient::createSurface to create a SurfaceControl, the SurfaceControl can create a Surface for drawing.

But what if you want to configure Surface’s zorder, position and other attributes?

Methods for configuring properties are provided in SurfaceComposerClient::Transaction.

SurfaceComposerClient::Transaction::setXXX()

For example, in “02 The Simplest SurfaceFlinger Application”, zorder is configured to be the largest, the display position is set to the middle of the screen, the current layer is set to visible, etc.

 SurfaceComposerClient::Transaction{}
            .setLayer(surfaceControl, std::numeric_limits<int32_t>::max())
            .setPosition(surfaceControl, (displayMode.resolution.getWidth() - 200) / 2,
                (displayMode.resolution.getHeight() - 200) / 2)
            .show(surfaceControl)
            .apply();

Take setLayer as an example to see how it works internally.

setLayer

1. First get LayerSate; it is actually layer_state_t in ComposerState; if it cannot be found in mComposerStates, create one, and return it directly if found.

2. Modify the value in state

SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setLayer(
        const sp<SurfaceControl> & amp; sc, int32_t z) {
    layer_state_t* s = getLayerState(sc);

    s->what |= layer_state_t::eLayerChanged;
    s->what & amp;= ~layer_state_t::eRelativeLayerChanged;
    s->z = z;
}
layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl> & amp; sc) {
    auto handle = sc->getLayerStateHandle();

    if (mComposerStates.count(handle) == 0) {
        // we don't have it, add an initialized layer_state to our list
        ComposerState s;

        s.state.surface = handle;
        s.state.layerId = sc->getLayerId();

        mComposerStates[handle] = s;
    }

    return &(mComposerStates[handle].state);
}

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

setPosition

SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setPosition(
        const sp<SurfaceControl> & amp; sc, float x, float y) {
    layer_state_t* s = getLayerState(sc);

    s->what |= layer_state_t::ePositionChanged;
    s->x = x;
    s->y = y;

    return *this;
}

show

SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::show(
        const sp<SurfaceControl> & amp; sc) {
    return setFlags(sc, 0, layer_state_t::eLayerHidden);
}

SurfaceComposerClient::Transaction & amp; SurfaceComposerClient::Transaction::setFlags(
        const sp<SurfaceControl> & amp; sc, uint32_t flags,
        uint32_t mask) {
    layer_state_t* s = getLayerState(sc);

    if ((mask & amp; layer_state_t::eLayerOpaque) || (mask & amp; layer_state_t::eLayerHidden) ||
        (mask & amp; layer_state_t::eLayerSecure) || (mask & amp; layer_state_t::eLayerSkipScreenshot) ||
        (mask & amp; layer_state_t::eEnableBackpressure)) {
        s->what |= layer_state_t::eFlagsChanged;
    }
    s->flags & amp;= ~mask;
    s->flags |= (flags & amp; mask);
    s->mask |= mask;

    return *this;
}

The implementation of other setting properties is basically the same and will not be explained one by one.

apply

After setting a bunch of parameters, when will it take effect? The answer is to execute apply

apply function:

  1. Put mComposerStates with configured layer parameters into composerStates
  2. mDisplayStates into displayStates
  3. Call sf->setTransactionState to commit the transaction
status_t SurfaceComposerClient::Transaction::apply(bool synchronous) {


    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    
    Vector<ComposerState> composerStates;
    Vector<DisplayState> displayStates;
    
    for (auto const & amp; kv : mComposerStates){
        composerStates.add(kv.second);
    }
    displayStates = std::move(mDisplayStates);

    sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
                            mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
                            {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
                            hasListenerCallbacks, listenerCallbacks, mId);
}

Will call SurfaceFlinger’s setTransactionState

status_t SurfaceFlinger::setTransactionState(
        const FrameTimelineInfo & amp; frameTimelineInfo, const Vector<ComposerState> & amp; states,
        const Vector<DisplayState> & amp; displays, uint32_t flags, const sp<IBinder> & amp; applyToken,
        const InputWindowCommands & amp; inputWindowCommands, int64_t desiredPresentTime,
        bool isAutoTimestamp, const client_cache_t & uncacheBuffer, bool hasListenerCallbacks,
        const std::vector<ListenerCallbacks> & amp; listenerCallbacks, uint64_t transactionId) {

   TransactionState state{frameTimelineInfo, states,
                           displays, flags,
                           applyToken, inputWindowCommands,
                           desiredPresentTime, isAutoTimestamp,
                           uncacheBuffer, postTime,
                           permissions, hasListenerCallbacks,
                           listenerCallbacks, originPid,
                           originUid, transactionId};

    queueTransaction(state);
}

void SurfaceFlinger::queueTransaction(TransactionState & amp; state) {
    mTransactionQueue.emplace(state);

    setTransactionFlags(eTransactionFlushNeeded, schedule, state.applyToken);
}

setTransactionState

main effect:

1. Create a TransactionState with the parameters passed in

2. Use queueTransaction to put the created state into the mTransactionQueue queue, set the eTransactionFlushNeeded flag; wait for the next vsync to come and retrieve it.

Draw a picture to summarize:

  1. Judging from the code, each surfacecontrol will only have one ComposerState.
  2. If apply is not executed, none of the parameters set above will take effect.
  3. Each apply will create a TransactionState and add it to SurfaceFlinger’s mTransactionQueue

Now that SurfaceFliger has obtained all the information of the layer, it can perform synthesis and refresh based on this information.

Creation is not easy, please like and comment.