Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8feddee9 authored by Rob Carr's avatar Rob Carr Committed by Android (Google) Code Review
Browse files

Merge "SurfaceFlinger: Share ownership of layers between State and Handle."

parents 7e86280f f478f9f7
Loading
Loading
Loading
Loading
+29 −18
Original line number Diff line number Diff line
@@ -119,13 +119,20 @@ Layer::~Layer() {
        c->detachLayer(this);
    }

    for (auto& point : mRemoteSyncPoints) {
        point->setTransactionApplied();
    }
    mFrameTracker.logAndResetStats(mName);

    // The remote sync points are cleared out when we are
    // removed from current state.
    Mutex::Autolock lock(mLocalSyncPointMutex);
    for (auto& point : mLocalSyncPoints) {
        point->setFrameAvailable();
    }
    mFrameTracker.logAndResetStats(mName);

    abandon();

    destroyAllHwcLayers();

    mFlinger->onLayerDestroyed();
}

// ---------------------------------------------------------------------------
@@ -140,10 +147,9 @@ Layer::~Layer() {
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}

void Layer::onRemovedFromCurrentState() {
    // the layer is removed from SF mCurrentState to mLayersPendingRemoval

    mPendingRemoval = true;
    mRemovedFromCurrentState = true;

    // the layer is removed from SF mCurrentState to mLayersPendingRemoval
    if (mCurrentState.zOrderRelativeOf != nullptr) {
        sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
        if (strongRelative != nullptr) {
@@ -153,19 +159,18 @@ void Layer::onRemovedFromCurrentState() {
        mCurrentState.zOrderRelativeOf = nullptr;
    }

    for (const auto& child : mCurrentChildren) {
        child->onRemovedFromCurrentState();
    }
    // Since we are no longer reachable from CurrentState SurfaceFlinger
    // will no longer invoke doTransaction for us, and so we will
    // never finish applying transactions. We signal the sync point
    // now so that another layer will not become indefinitely
    // blocked.
    for (auto& point: mRemoteSyncPoints) {
        point->setTransactionApplied();
    }

void Layer::onRemoved() {
    // the layer is removed from SF mLayersPendingRemoval
    abandon();

    destroyAllHwcLayers();
    mRemoteSyncPoints.clear();

    for (const auto& child : mCurrentChildren) {
        child->onRemoved();
        child->onRemovedFromCurrentState();
    }
}

@@ -228,6 +233,10 @@ void Layer::destroyAllHwcLayers() {
    }
    LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
                        "All hardware composer layers should have been destroyed");

    for (const sp<Layer>& child : mDrawingChildren) {
        child->destroyAllHwcLayers();
    }
}

Rect Layer::getContentCrop() const {
@@ -825,7 +834,9 @@ void Layer::pushPendingState() {

    // If this transaction is waiting on the receipt of a frame, generate a sync
    // point and send it to the remote layer.
    if (mCurrentState.barrierLayer_legacy != nullptr) {
    // We don't allow installing sync points after we are removed from the current state
    // as we won't be able to signal our end.
    if (mCurrentState.barrierLayer_legacy != nullptr && !mRemovedFromCurrentState) {
        sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
        if (barrierLayer == nullptr) {
            ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
+6 −10
Original line number Diff line number Diff line
@@ -346,7 +346,7 @@ public:
    virtual bool isCreatedFromMainThread() const { return false; }


    bool isPendingRemoval() const { return mPendingRemoval; }
    bool isRemovedFromCurrentState() const { return mRemovedFromCurrentState; }

    void writeToProto(LayerProto* layerInfo,
                      LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
@@ -475,12 +475,6 @@ public:
     */
    void onRemovedFromCurrentState();

    /*
     * called with the state lock from the main thread when the layer is
     * removed from the pending removal list
     */
    void onRemoved();

    // Updates the transform hint in our SurfaceFlingerConsumer to match
    // the current orientation of the display device.
    void updateTransformHint(const sp<const DisplayDevice>& display) const;
@@ -595,12 +589,12 @@ protected:
     */
    class LayerCleaner {
        sp<SurfaceFlinger> mFlinger;
        wp<Layer> mLayer;
        sp<Layer> mLayer;

    protected:
        ~LayerCleaner() {
            // destroy client resources
            mFlinger->onLayerDestroyed(mLayer);
            mFlinger->onHandleDestroyed(mLayer);
        }

    public:
@@ -702,6 +696,8 @@ public:
    virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
    bool getPremultipledAlpha() const;

    bool mPendingHWCDestroy{false};

protected:
    // -----------------------------------------------------------------------
    bool usingRelativeZ(LayerVector::StateSet stateSet);
@@ -745,7 +741,7 @@ protected:
    // Whether filtering is needed b/c of the drawingstate
    bool mNeedsFiltering{false};

    bool mPendingRemoval{false};
    bool mRemovedFromCurrentState{false};

    // page-flip thread (currently main thread)
    bool mProtectedByApp{false}; // application requires protected path to external sink
+21 −59
Original line number Diff line number Diff line
@@ -2715,7 +2715,14 @@ void SurfaceFlinger::commitTransaction()
        for (const auto& l : mLayersPendingRemoval) {
            recordBufferingStats(l->getName().string(),
                    l->getOccupancyHistory(true));
            l->onRemoved();

            // We need to release the HWC layers when the Layer is removed
            // from the current state otherwise the HWC layer just continues
            // showing at it's last configured state until we eventually
            // abandon the buffer queue.
            if (l->isRemovedFromCurrentState()) {
                l->destroyAllHwcLayers();
            }
        }
        mLayersPendingRemoval.clear();
    }
@@ -3148,10 +3155,6 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client,
        if (parent == nullptr) {
            mCurrentState.layersSortedByZ.add(lbc);
        } else {
            if (parent->isPendingRemoval()) {
                ALOGE("addClientLayer called with a removed parent");
                return NAME_NOT_FOUND;
            }
            parent->addChild(lbc);
        }

@@ -3178,52 +3181,22 @@ status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer, bool topLevelOnly)
    return removeLayerLocked(mStateLock, layer, topLevelOnly);
}

status_t SurfaceFlinger::removeLayerLocked(const Mutex&, const sp<Layer>& layer,
status_t SurfaceFlinger::removeLayerLocked(const Mutex& lock, const sp<Layer>& layer,
                                           bool topLevelOnly) {
    if (layer->isPendingRemoval()) {
        return NO_ERROR;
    }

    const auto& p = layer->getParent();
    ssize_t index;
    if (p != nullptr) {
        if (topLevelOnly) {
            return NO_ERROR;
        }

        sp<Layer> ancestor = p;
        while (ancestor->getParent() != nullptr) {
            ancestor = ancestor->getParent();
        }
        if (mCurrentState.layersSortedByZ.indexOf(ancestor) < 0) {
            ALOGE("removeLayer called with a layer whose parent has been removed");
            return NAME_NOT_FOUND;
        }

        index = p->removeChild(layer);
    } else {
        index = mCurrentState.layersSortedByZ.remove(layer);
    }

    // As a matter of normal operation, the LayerCleaner will produce a second
    // attempt to remove the surface. The Layer will be kept alive in mDrawingState
    // so we will succeed in promoting it, but it's already been removed
    // from mCurrentState. As long as we can find it in mDrawingState we have no problem
    // otherwise something has gone wrong and we are leaking the layer.
    if (index < 0 && mDrawingState.layersSortedByZ.indexOf(layer) < 0) {
        ALOGE("Failed to find layer (%s) in layer parent (%s).",
                layer->getName().string(),
                (p != nullptr) ? p->getName().string() : "no-parent");
        return BAD_VALUE;
    } else if (index < 0) {
        return NO_ERROR;
    }

    layer->onRemovedFromCurrentState();
    mLayersPendingRemoval.add(layer);
    mLayersRemoved = true;
    mNumLayers -= 1 + layer->getChildrenCount();
    setTransactionFlags(eTransactionNeeded);

    markLayerPendingRemovalLocked(lock, layer);
    return NO_ERROR;
}

@@ -3424,11 +3397,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState
        return 0;
    }

    if (layer->isPendingRemoval()) {
        ALOGW("Attempting to set client state on removed layer: %s", layer->getName().string());
        return 0;
    }

    uint32_t flags = 0;

    const uint32_t what = s.what;
@@ -3632,11 +3600,6 @@ void SurfaceFlinger::setDestroyStateLocked(const ComposerState& composerState) {
        return;
    }

    if (layer->isPendingRemoval()) {
        ALOGW("Attempting to destroy on removed layer: %s", layer->getName().string());
        return;
    }

    if (state.what & layer_state_t::eDestroySurface) {
        removeLayerLocked(mStateLock, layer);
    }
@@ -3809,17 +3772,16 @@ status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBind
    return err;
}

status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer)
{
    // called by ~LayerCleaner() when all references to the IBinder (handle)
    // are gone
    sp<Layer> l = layer.promote();
    if (l == nullptr) {
        // The layer has already been removed, carry on
        return NO_ERROR;
void SurfaceFlinger::markLayerPendingRemovalLocked(const Mutex&, const sp<Layer>& layer) {
    mLayersPendingRemoval.add(layer);
    mLayersRemoved = true;
    setTransactionFlags(eTransactionNeeded);
}
    // If we have a parent, then we can continue to live as long as it does.
    return removeLayer(l, true);

void SurfaceFlinger::onHandleDestroyed(const sp<Layer>& layer)
{
    Mutex::Autolock lock(mStateLock);
    markLayerPendingRemovalLocked(mStateLock, layer);
}

// ---------------------------------------------------------------------------
@@ -5212,7 +5174,7 @@ status_t SurfaceFlinger::captureLayers(const sp<IBinder>& layerHandleBinder,
    auto layerHandle = reinterpret_cast<Layer::Handle*>(layerHandleBinder.get());
    auto parent = layerHandle->owner.promote();

    if (parent == nullptr || parent->isPendingRemoval()) {
    if (parent == nullptr || parent->isRemovedFromCurrentState()) {
        ALOGE("captureLayers called with a removed parent");
        return NAME_NOT_FOUND;
    }
+5 −1
Original line number Diff line number Diff line
@@ -356,6 +356,8 @@ public:
    bool authenticateSurfaceTextureLocked(
        const sp<IGraphicBufferProducer>& bufferProducer) const;

    inline void onLayerDestroyed() { mNumLayers--; }

private:
    friend class Client;
    friend class DisplayEventConnection;
@@ -561,10 +563,12 @@ private:
    // ISurfaceComposerClient::destroySurface()
    status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);

    void markLayerPendingRemovalLocked(const Mutex& /* mStateLock */, const sp<Layer>& layer);

    // called when all clients have released all their references to
    // this layer meaning it is entirely safe to destroy all
    // resources associated to this layer.
    status_t onLayerDestroyed(const wp<Layer>& layer);
    void onHandleDestroyed(const sp<Layer>& layer);

    // remove a layer from SurfaceFlinger immediately
    status_t removeLayer(const sp<Layer>& layer, bool topLevelOnly = false);
+31 −0
Original line number Diff line number Diff line
@@ -2550,6 +2550,37 @@ TEST_F(ChildLayerTest, ReparentChildren) {
    }
}

TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
    sp<SurfaceControl> mGrandChild =
        mClient->createSurface(String8("Grand Child"), 10, 10,
                PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
    fillSurfaceRGBA8(mGrandChild, 111, 111, 111);

    {
        SCOPED_TRACE("Grandchild visible");
        ScreenCapture::captureScreen(&mCapture);
        mCapture->checkPixel(64, 64, 111, 111, 111);
    }

    mChild->clear();

    {
        SCOPED_TRACE("After destroying child");
        ScreenCapture::captureScreen(&mCapture);
        mCapture->expectFGColor(64, 64);
    }

    asTransaction([&](Transaction& t) {
         t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
    });

    {
        SCOPED_TRACE("After reparenting grandchild");
        ScreenCapture::captureScreen(&mCapture);
        mCapture->checkPixel(64, 64, 111, 111, 111);
    }
}

TEST_F(ChildLayerTest, DetachChildrenSameClient) {
    asTransaction([&](Transaction& t) {
        t.show(mChild);