diff options
-rw-r--r-- | include/gui/SurfaceComposerClient.h | 1 | ||||
-rw-r--r-- | include/gui/SurfaceControl.h | 12 | ||||
-rw-r--r-- | include/private/gui/LayerState.h | 1 | ||||
-rw-r--r-- | libs/gui/SurfaceComposerClient.cpp | 18 | ||||
-rw-r--r-- | libs/gui/SurfaceControl.cpp | 6 | ||||
-rw-r--r-- | services/surfaceflinger/Client.cpp | 5 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.cpp | 15 | ||||
-rw-r--r-- | services/surfaceflinger/Layer.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 24 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger_hwc1.cpp | 24 | ||||
-rw-r--r-- | services/surfaceflinger/tests/Transaction_test.cpp | 64 |
12 files changed, 151 insertions, 22 deletions
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index df73ff61ee..520a7ab9b1 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -160,6 +160,7 @@ public: const sp<Surface>& handle, uint64_t frameNumber); status_t reparentChildren(const sp<IBinder>& id, const sp<IBinder>& newParentHandle); + status_t detachChildren(const sp<IBinder>& id); status_t setOverrideScalingMode(const sp<IBinder>& id, int32_t overrideScalingMode); status_t setGeometryAppliesWithResize(const sp<IBinder>& id); diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h index 8d338f98a8..58ec6dce2a 100644 --- a/include/gui/SurfaceControl.h +++ b/include/gui/SurfaceControl.h @@ -93,6 +93,18 @@ public: // Reparents all children of this layer to the new parent handle. status_t reparentChildren(const sp<IBinder>& newParentHandle); + // Detaches all child surfaces (and their children recursively) + // from their SurfaceControl. + // The child SurfaceControl's will not throw exceptions or return errors, + // but transactions will have no effect. + // The child surfaces will continue to follow their parent surfaces, + // and remain eligible for rendering, but their relative state will be + // frozen. We use this in the WindowManager, in app shutdown/relaunch + // scenarios, where the app would otherwise clean up its child Surfaces. + // Sometimes the WindowManager needs to extend their lifetime slightly + // in order to perform an exit animation or prevent flicker. + status_t detachChildren(); + // Set an override scaling mode as documented in <system/window.h> // the override scaling mode will take precedence over any client // specified scaling mode. -1 will clear the override scaling mode. diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index fac5d2cb75..6d2b0825aa 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -58,6 +58,7 @@ struct layer_state_t { eOverrideScalingModeChanged = 0x00000800, eGeometryAppliesWithResize = 0x00001000, eReparentChildren = 0x00002000, + eDetachChildren = 0x00004000 }; layer_state_t() diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index fd277f1beb..2632781982 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -175,6 +175,8 @@ public: status_t reparentChildren(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, const sp<IBinder>& newParentHandle); + status_t detachChildren(const sp<SurfaceComposerClient>& client, + const sp<IBinder>& id); status_t setOverrideScalingMode(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, int32_t overrideScalingMode); status_t setGeometryAppliesWithResize(const sp<SurfaceComposerClient>& client, @@ -476,6 +478,18 @@ status_t Composer::reparentChildren( return NO_ERROR; } +status_t Composer::detachChildren( + const sp<SurfaceComposerClient>& client, + const sp<IBinder>& id) { + Mutex::Autolock lock(mLock); + layer_state_t* s = getLayerStateLocked(client, id); + if (!s) { + return BAD_INDEX; + } + s->what |= layer_state_t::eDetachChildren; + return NO_ERROR; +} + status_t Composer::setOverrideScalingMode( const sp<SurfaceComposerClient>& client, const sp<IBinder>& id, int32_t overrideScalingMode) { @@ -805,6 +819,10 @@ status_t SurfaceComposerClient::reparentChildren(const sp<IBinder>& id, return getComposer().reparentChildren(this, id, newParentHandle); } +status_t SurfaceComposerClient::detachChildren(const sp<IBinder>& id) { + return getComposer().detachChildren(this, id); +} + status_t SurfaceComposerClient::setOverrideScalingMode( const sp<IBinder>& id, int32_t overrideScalingMode) { return getComposer().setOverrideScalingMode( diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 94094e5a51..0080ff9812 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -183,6 +183,12 @@ status_t SurfaceControl::reparentChildren(const sp<IBinder>& newParentHandle) { return mClient->reparentChildren(mHandle, newParentHandle); } +status_t SurfaceControl::detachChildren() { + status_t err = validate(); + if (err < 0) return err; + return mClient->detachChildren(mHandle); +} + status_t SurfaceControl::setOverrideScalingMode(int32_t overrideScalingMode) { status_t err = validate(); if (err < 0) return err; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 2b4f4cb6fd..9ddae2b4dc 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -49,7 +49,10 @@ Client::~Client() { const size_t count = mLayers.size(); for (size_t i=0 ; i<count ; i++) { - mFlinger->removeLayer(mLayers.valueAt(i)); + sp<Layer> l = mLayers.valueAt(i).promote(); + if (l != nullptr) { + mFlinger->removeLayer(l); + } } } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 6908c883fd..9b02d3e616 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2455,6 +2455,21 @@ bool Layer::reparentChildren(const sp<IBinder>& newParentHandle) { return true; } +bool Layer::detachChildren() { + traverseInZOrder([this](Layer* child) { + if (child == this) { + return; + } + + sp<Client> client(child->mClientRef.promote()); + if (client != nullptr) { + client->detachLayer(child); + } + }); + + return true; +} + void Layer::setParent(const sp<Layer>& layer) { mParent = layer; } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index fc33c99373..f2e5f2284d 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -176,6 +176,7 @@ public: bool setOverrideScalingMode(int32_t overrideScalingMode); void setInfo(uint32_t type, uint32_t appId); bool reparentChildren(const sp<IBinder>& layer); + bool detachChildren(); // If we have received a new buffer this frame, we will pass its surface // damage down to hardware composer. Otherwise, we must send a region with diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7a31a1528c..62c9f25da3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2534,14 +2534,7 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, return NO_ERROR; } -status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) { - Mutex::Autolock _l(mStateLock); - sp<Layer> layer = weakLayer.promote(); - if (layer == nullptr) { - // The layer has already been removed, carry on - return NO_ERROR; - } - +status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { const auto& p = layer->getParent(); const ssize_t index = (p != nullptr) ? p->removeChild(layer) : mCurrentState.layersSortedByZ.remove(layer); @@ -2824,6 +2817,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded|eTraversalNeeded; } } + if (what & layer_state_t::eDetachChildren) { + layer->detachChildren(); + } if (what & layer_state_t::eOverrideScalingModeChanged) { layer->setOverrideScalingMode(s.overrideScalingMode); // We don't trigger a traversal here because if no other state is @@ -2920,7 +2916,7 @@ status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle) { - // called by the window manager when it wants to remove a Layer + // called by a client when it wants to remove a Layer status_t err = NO_ERROR; sp<Layer> l(client->getLayerUser(handle)); if (l != NULL) { @@ -2936,7 +2932,15 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer) { // called by ~LayerCleaner() when all references to the IBinder (handle) // are gone - return removeLayer(layer); + sp<Layer> l = layer.promote(); + if (l == nullptr) { + // The layer has already been removed, carry on + return NO_ERROR; + } if (l->getParent() != nullptr) { + // If we have a parent, then we can continue to live as long as it does. + return NO_ERROR; + } + return removeLayer(l); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 970a4ef125..5bdedf3af3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -332,7 +332,7 @@ private: status_t onLayerDestroyed(const wp<Layer>& layer); // remove a layer from SurfaceFlinger immediately - status_t removeLayer(const wp<Layer>& layer); + status_t removeLayer(const sp<Layer>& layer); // add a layer to SurfaceFlinger status_t addClientLayer(const sp<Client>& client, diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp index 056d733089..9aa2fabf8c 100644 --- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp +++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp @@ -2318,14 +2318,7 @@ status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, return NO_ERROR; } -status_t SurfaceFlinger::removeLayer(const wp<Layer>& weakLayer) { - Mutex::Autolock _l(mStateLock); - sp<Layer> layer = weakLayer.promote(); - if (layer == nullptr) { - // The layer has already been removed, carry on - return NO_ERROR; - } - +status_t SurfaceFlinger::removeLayer(const sp<Layer>& layer) { const auto& p = layer->getParent(); const ssize_t index = (p != nullptr) ? p->removeChild(layer) : mCurrentState.layersSortedByZ.remove(layer); @@ -2608,6 +2601,9 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTransactionNeeded|eTraversalNeeded; } } + if (what & layer_state_t::eDetachChildren) { + layer->detachChildren(); + } if (what & layer_state_t::eOverrideScalingModeChanged) { layer->setOverrideScalingMode(s.overrideScalingMode); // We don't trigger a traversal here because if no other state is @@ -2704,7 +2700,7 @@ status_t SurfaceFlinger::createDimLayer(const sp<Client>& client, status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle) { - // called by the window manager when it wants to remove a Layer + // called by a client when it wants to remove a Layer status_t err = NO_ERROR; sp<Layer> l(client->getLayerUser(handle)); if (l != NULL) { @@ -2720,7 +2716,15 @@ status_t SurfaceFlinger::onLayerDestroyed(const wp<Layer>& layer) { // called by ~LayerCleaner() when all references to the IBinder (handle) // are gone - return removeLayer(layer); + sp<Layer> l = layer.promote(); + if (l == nullptr) { + // The layer has already been removed, carry on + return NO_ERROR; + } if (l->getParent() != nullptr) { + // If we have a parent, then we can continue to live as long as it does. + return NO_ERROR; + } + return removeLayer(l); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index d9f1438026..5b61ae0e9b 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -630,4 +630,68 @@ TEST_F(ChildLayerTest, ChildLayerScaling) { mCapture->expectFGColor(20, 20); } } + +TEST_F(ChildLayerTest, ReparentChildren) { + SurfaceComposerClient::openGlobalTransaction(); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + SurfaceComposerClient::closeGlobalTransaction(true); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // But 10 pixels in we should see the child surface + mCapture->expectChildColor(74, 74); + // And 10 more pixels we should be back to the foreground surface + mCapture->expectFGColor(84, 84); + } + mFGSurfaceControl->reparentChildren(mBGSurfaceControl->getHandle()); + { + ScreenCapture::captureScreen(&mCapture); + mCapture->expectFGColor(64, 64); + // In reparenting we should have exposed the entire foreground surface. + mCapture->expectFGColor(74, 74); + // And the child layer should now begin at 10, 10 (since the BG + // layer is at (0, 0)). + mCapture->expectBGColor(9, 9); + mCapture->expectChildColor(10, 10); + } +} + +TEST_F(ChildLayerTest, DetachChildren) { + SurfaceComposerClient::openGlobalTransaction(); + mChild->show(); + mChild->setPosition(10, 10); + mFGSurfaceControl->setPosition(64, 64); + SurfaceComposerClient::closeGlobalTransaction(true); + + { + ScreenCapture::captureScreen(&mCapture); + // Top left of foreground must now be visible + mCapture->expectFGColor(64, 64); + // But 10 pixels in we should see the child surface + mCapture->expectChildColor(74, 74); + // And 10 more pixels we should be back to the foreground surface + mCapture->expectFGColor(84, 84); + } + + SurfaceComposerClient::openGlobalTransaction(); + mFGSurfaceControl->detachChildren(); + SurfaceComposerClient::closeGlobalTransaction(); + + SurfaceComposerClient::openGlobalTransaction(); + mChild->hide(); + SurfaceComposerClient::closeGlobalTransaction(); + + // Nothing should have changed. + { + ScreenCapture::captureScreen(&mCapture); + mCapture->expectFGColor(64, 64); + mCapture->expectChildColor(74, 74); + mCapture->expectFGColor(84, 84); + } +} + } |