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

Commit 14d7692c authored by Vishnu Nair's avatar Vishnu Nair
Browse files

Reparent children before reparenting to null

When we reparent a layer to null, we remove its child layers from current state and remove
their relative z. If the children are reparented in the same transaction, then we have to
make sure we reparent the children first so we do not lose their relative z order.

Test: atest SurfaceFlinger_test
Bug: 132205507
Change-Id: I6b73758065c7eb46ac3b60a1b40f6839be24b09c
parent 61eba0db
Loading
Loading
Loading
Loading
+13 −9
Original line number Diff line number Diff line
@@ -4052,15 +4052,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(
        // We don't trigger a traversal here because if no other state is
        // changed, we don't want this to cause any more work
    }
    if (what & layer_state_t::eReparent) {
        bool hadParent = layer->hasParent();
        if (layer->reparent(s.parentHandleForChild)) {
            if (!hadParent) {
                mCurrentState.layersSortedByZ.remove(layer);
            }
            flags |= eTransactionNeeded|eTraversalNeeded;
        }
    }
    if (what & layer_state_t::eReparentChildren) {
        if (layer->reparentChildren(s.reparentHandle)) {
            flags |= eTransactionNeeded|eTraversalNeeded;
@@ -4121,6 +4112,19 @@ uint32_t SurfaceFlinger::setClientStateLocked(
            flags |= eTraversalNeeded;
        }
    }
    // This has to happen after we reparent children because when we reparent to null we remove
    // child layers from current state and remove its relative z. If the children are reparented in
    // the same transaction, then we have to make sure we reparent the children first so we do not
    // lose its relative z order.
    if (what & layer_state_t::eReparent) {
        bool hadParent = layer->hasParent();
        if (layer->reparent(s.parentHandleForChild)) {
            if (!hadParent) {
                mCurrentState.layersSortedByZ.remove(layer);
            }
            flags |= eTransactionNeeded | eTraversalNeeded;
        }
    }
    std::vector<sp<CallbackHandle>> callbackHandles;
    if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
        for (const auto& [listener, callbackIds] : listenerCallbacks) {
+28 −0
Original line number Diff line number Diff line
@@ -4686,6 +4686,34 @@ TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
    }
}

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

    // draw grand child behind the foreground surface
    asTransaction([&](Transaction& t) {
        t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
    });

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

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

    {
        SCOPED_TRACE("foreground visible reparenting grandchild");
        ScreenCapture::captureScreen(&mCapture);
        mCapture->checkPixel(64, 64, 195, 63, 63);
    }
}

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