diff options
| author | 2022-11-22 18:18:12 +0000 | |
|---|---|---|
| committer | 2022-11-22 18:18:12 +0000 | |
| commit | 898eca1ef77988be89a6ed44b41ffba74aa9c09c (patch) | |
| tree | 8b5f483f05e3d896ec2e784d1833c63eedd93b18 | |
| parent | fd2e7d3223b688f5a39cbb8de8418f48ccb4af0d (diff) | |
| parent | dc4d31bc876d5965bfe68b5f84db9b5149613131 (diff) | |
Merge "SF: Introduce LayerLifecycleManager"
| -rw-r--r-- | libs/gui/include/gui/WindowInfo.h | 1 | ||||
| -rw-r--r-- | services/surfaceflinger/Android.bp | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp | 317 | ||||
| -rw-r--r-- | services/surfaceflinger/FrontEnd/LayerLifecycleManager.h | 95 | ||||
| -rw-r--r-- | services/surfaceflinger/FrontEnd/RequestedLayerState.cpp | 358 | ||||
| -rw-r--r-- | services/surfaceflinger/FrontEnd/RequestedLayerState.h | 102 | ||||
| -rw-r--r-- | services/surfaceflinger/FrontEnd/SwapErase.h | 45 | ||||
| -rw-r--r-- | services/surfaceflinger/Layer.h | 2 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/Android.bp | 1 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp | 453 |
10 files changed, 1375 insertions, 1 deletions
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index ac74c8a91f..b01a3db52d 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -272,6 +272,7 @@ public: WindowInfoHandle(const WindowInfo& other); inline const WindowInfo* getInfo() const { return &mInfo; } + inline WindowInfo* editInfo() { return &mInfo; } sp<IBinder> getToken() const; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 14fdd126dd..b1bd705f19 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -157,6 +157,8 @@ filegroup { "EventLog/EventLog.cpp", "FrontEnd/LayerCreationArgs.cpp", "FrontEnd/LayerHandle.cpp", + "FrontEnd/LayerLifecycleManager.cpp", + "FrontEnd/RequestedLayerState.cpp", "FrontEnd/TransactionHandler.cpp", "FlagManager.cpp", "FpsReporter.cpp", diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp new file mode 100644 index 0000000000..1108246e47 --- /dev/null +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp @@ -0,0 +1,317 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#undef LOG_TAG +#define LOG_TAG "LayerLifecycleManager" + +#include "LayerLifecycleManager.h" +#include "Layer.h" // temporarily needed for LayerHandle +#include "LayerHandle.h" +#include "SwapErase.h" + +namespace android::surfaceflinger::frontend { + +using namespace ftl::flag_operators; + +void LayerLifecycleManager::addLayers(std::vector<std::unique_ptr<RequestedLayerState>> newLayers) { + if (newLayers.empty()) { + return; + } + + mGlobalChanges |= RequestedLayerState::Changes::Hierarchy; + for (auto& newLayer : newLayers) { + RequestedLayerState& layer = *newLayer.get(); + auto [it, inserted] = mIdToLayer.try_emplace(layer.id, References{.owner = layer}); + if (!inserted) { + LOG_ALWAYS_FATAL("Duplicate layer id %d found. Existing layer: %s", layer.id, + it->second.owner.getDebugString().c_str()); + } + + linkLayer(layer.parentId, layer.id); + linkLayer(layer.relativeParentId, layer.id); + linkLayer(layer.mirrorId, layer.id); + linkLayer(layer.touchCropId, layer.id); + + mLayers.emplace_back(std::move(newLayer)); + } +} + +void LayerLifecycleManager::onHandlesDestroyed(const std::vector<uint32_t>& destroyedHandles) { + std::vector<uint32_t> layersToBeDestroyed; + for (const auto& layerId : destroyedHandles) { + auto it = mIdToLayer.find(layerId); + if (it == mIdToLayer.end()) { + LOG_ALWAYS_FATAL("%s Layerid not found %d", __func__, layerId); + continue; + } + RequestedLayerState& layer = it->second.owner; + layer.handleAlive = false; + if (!layer.canBeDestroyed()) { + continue; + } + layer.changes |= RequestedLayerState::Changes::Destroyed; + layersToBeDestroyed.emplace_back(layerId); + } + + if (layersToBeDestroyed.empty()) { + return; + } + + mGlobalChanges |= RequestedLayerState::Changes::Hierarchy; + for (size_t i = 0; i < layersToBeDestroyed.size(); i++) { + uint32_t layerId = layersToBeDestroyed[i]; + auto it = mIdToLayer.find(layerId); + if (it == mIdToLayer.end()) { + LOG_ALWAYS_FATAL("%s Layer with id %d not found", __func__, layerId); + continue; + } + + RequestedLayerState& layer = it->second.owner; + + unlinkLayer(layer.parentId, layer.id); + unlinkLayer(layer.relativeParentId, layer.id); + unlinkLayer(layer.mirrorId, layer.id); + unlinkLayer(layer.touchCropId, layer.id); + + auto& references = it->second.references; + for (uint32_t linkedLayerId : references) { + RequestedLayerState* linkedLayer = getLayerFromId(linkedLayerId); + if (!linkedLayer) { + LOG_ALWAYS_FATAL("%s Layerid reference %d not found for %d", __func__, + linkedLayerId, layer.id); + continue; + }; + if (linkedLayer->parentId == layer.id) { + linkedLayer->parentId = UNASSIGNED_LAYER_ID; + if (linkedLayer->canBeDestroyed()) { + linkedLayer->changes |= RequestedLayerState::Changes::Destroyed; + layersToBeDestroyed.emplace_back(linkedLayer->id); + } + } + if (linkedLayer->relativeParentId == layer.id) { + linkedLayer->relativeParentId = UNASSIGNED_LAYER_ID; + } + if (linkedLayer->mirrorId == layer.id) { + linkedLayer->mirrorId = UNASSIGNED_LAYER_ID; + } + if (linkedLayer->touchCropId == layer.id) { + linkedLayer->touchCropId = UNASSIGNED_LAYER_ID; + } + } + mIdToLayer.erase(it); + } + + auto it = mLayers.begin(); + while (it != mLayers.end()) { + RequestedLayerState* layer = it->get(); + if (layer->changes.test(RequestedLayerState::Changes::Destroyed)) { + ALOGV("%s destroyed layer %s", __func__, layer->getDebugStringShort().c_str()); + std::iter_swap(it, mLayers.end() - 1); + mDestroyedLayers.emplace_back(std::move(mLayers.back())); + mLayers.erase(mLayers.end() - 1); + } else { + it++; + } + } +} + +void LayerLifecycleManager::applyTransactions(const std::vector<TransactionState>& transactions) { + for (const auto& transaction : transactions) { + for (const auto& resolvedComposerState : transaction.states) { + const auto& clientState = resolvedComposerState.state; + uint32_t layerId = LayerHandle::getLayerId(clientState.surface); + if (layerId == UNASSIGNED_LAYER_ID) { + ALOGW("%s Handle %p is not valid", __func__, clientState.surface.get()); + continue; + } + + RequestedLayerState* layer = getLayerFromId(layerId); + if (layer == nullptr) { + LOG_ALWAYS_FATAL("%s Layer with handle %p (layerid=%d) not found", __func__, + clientState.surface.get(), layerId); + continue; + } + + if (!layer->handleAlive) { + LOG_ALWAYS_FATAL("%s Layer's handle %p (layerid=%d) is not alive. Possible out of " + "order LayerLifecycleManager updates", + __func__, clientState.surface.get(), layerId); + continue; + } + + uint32_t oldParentId = layer->parentId; + uint32_t oldRelativeParentId = layer->relativeParentId; + uint32_t oldTouchCropId = layer->touchCropId; + layer->merge(resolvedComposerState); + + if (layer->what & layer_state_t::eBackgroundColorChanged) { + if (layer->bgColorLayerId == UNASSIGNED_LAYER_ID && layer->bgColorAlpha != 0) { + LayerCreationArgs backgroundLayerArgs{nullptr, + nullptr, + layer->name + "BackgroundColorLayer", + ISurfaceComposerClient::eFXSurfaceEffect, + {}}; + std::vector<std::unique_ptr<RequestedLayerState>> newLayers; + newLayers.emplace_back( + std::make_unique<RequestedLayerState>(backgroundLayerArgs)); + RequestedLayerState* backgroundLayer = newLayers.back().get(); + backgroundLayer->handleAlive = false; + backgroundLayer->parentId = layer->id; + backgroundLayer->z = std::numeric_limits<int32_t>::min(); + backgroundLayer->color.rgb = layer->color.rgb; + backgroundLayer->color.a = layer->bgColorAlpha; + backgroundLayer->dataspace = layer->bgColorDataspace; + + layer->bgColorLayerId = backgroundLayer->id; + addLayers({std::move(newLayers)}); + } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID && + layer->bgColorAlpha == 0) { + RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId); + bgColorLayer->parentId = UNASSIGNED_LAYER_ID; + onHandlesDestroyed({layer->bgColorLayerId}); + } else if (layer->bgColorLayerId != UNASSIGNED_LAYER_ID) { + RequestedLayerState* bgColorLayer = getLayerFromId(layer->bgColorLayerId); + bgColorLayer->color.rgb = layer->color.rgb; + bgColorLayer->color.a = layer->bgColorAlpha; + bgColorLayer->dataspace = layer->bgColorDataspace; + mGlobalChanges |= RequestedLayerState::Changes::Content; + } + } + + if (oldParentId != layer->parentId) { + unlinkLayer(oldParentId, layer->id); + linkLayer(layer->parentId, layer->id); + } + if (oldRelativeParentId != layer->relativeParentId) { + unlinkLayer(oldRelativeParentId, layer->id); + linkLayer(layer->relativeParentId, layer->id); + } + if (oldTouchCropId != layer->touchCropId) { + unlinkLayer(oldTouchCropId, layer->id); + linkLayer(layer->touchCropId, layer->id); + } + + mGlobalChanges |= layer->changes & + (RequestedLayerState::Changes::Hierarchy | + RequestedLayerState::Changes::Geometry | + RequestedLayerState::Changes::Content); + } + } +} + +void LayerLifecycleManager::commitChanges() { + for (auto& layer : mLayers) { + if (layer->changes.test(RequestedLayerState::Changes::Created)) { + for (auto listener : mListeners) { + listener->onLayerAdded(*layer); + } + } + layer->what = 0; + layer->changes.clear(); + } + + for (auto& destroyedLayer : mDestroyedLayers) { + if (destroyedLayer->changes.test(RequestedLayerState::Changes::Created)) { + for (auto listener : mListeners) { + listener->onLayerAdded(*destroyedLayer); + } + } + + for (auto listener : mListeners) { + listener->onLayerDestroyed(*destroyedLayer); + } + } + mDestroyedLayers.clear(); + mGlobalChanges.clear(); +} + +void LayerLifecycleManager::addLifecycleListener(std::shared_ptr<ILifecycleListener> listener) { + mListeners.emplace_back(std::move(listener)); +} + +void LayerLifecycleManager::removeLifecycleListener(std::shared_ptr<ILifecycleListener> listener) { + swapErase(mListeners, listener); +} + +const std::vector<std::unique_ptr<RequestedLayerState>>& LayerLifecycleManager::getLayers() const { + return mLayers; +} + +const std::vector<std::unique_ptr<RequestedLayerState>>& LayerLifecycleManager::getDestroyedLayers() + const { + return mDestroyedLayers; +} + +const ftl::Flags<RequestedLayerState::Changes> LayerLifecycleManager::getGlobalChanges() const { + return mGlobalChanges; +} + +RequestedLayerState* LayerLifecycleManager::getLayerFromId(uint32_t id) { + if (id == UNASSIGNED_LAYER_ID) { + return nullptr; + } + auto it = mIdToLayer.find(id); + if (it == mIdToLayer.end()) { + return nullptr; + } + return &it->second.owner; +} + +std::vector<uint32_t>* LayerLifecycleManager::getLinkedLayersFromId(uint32_t id) { + if (id == UNASSIGNED_LAYER_ID) { + return nullptr; + } + auto it = mIdToLayer.find(id); + if (it == mIdToLayer.end()) { + return nullptr; + } + return &it->second.references; +} + +void LayerLifecycleManager::linkLayer(uint32_t layerId, uint32_t layerToLink) { + if (layerToLink && layerId != UNASSIGNED_LAYER_ID) { + std::vector<uint32_t>* linkedLayers = getLinkedLayersFromId(layerId); + if (!linkedLayers) { + LOG_ALWAYS_FATAL("Could not find layer id %d to link %d", layerId, layerToLink); + return; + } + linkedLayers->emplace_back(layerToLink); + } +} + +void LayerLifecycleManager::unlinkLayer(uint32_t& inOutLayerId, uint32_t linkedLayer) { + uint32_t layerId = inOutLayerId; + inOutLayerId = UNASSIGNED_LAYER_ID; + + std::vector<uint32_t>* linkedLayers = getLinkedLayersFromId(layerId); + if (!linkedLayers) { + return; + } + swapErase(*linkedLayers, linkedLayer); +} + +std::string LayerLifecycleManager::References::getDebugString() const { + std::string debugInfo = owner.name + "[" + std::to_string(owner.id) + "] refs:"; + std::for_each(references.begin(), references.end(), + [&debugInfo = debugInfo](const uint32_t& reference) mutable { + debugInfo += std::to_string(reference) + ","; + }); + return debugInfo; +} + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h new file mode 100644 index 0000000000..ad70d3f8e9 --- /dev/null +++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h @@ -0,0 +1,95 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "RequestedLayerState.h" +#include "TransactionState.h" + +namespace android::surfaceflinger::frontend { + +// Owns a collection of RequestedLayerStates and manages their lifecycle +// and state changes. +// +// RequestedLayerStates are tracked and destroyed if they have no parent and +// no handle left to keep them alive. The handle does not keep a reference to +// the RequestedLayerState but a layer id associated with the RequestedLayerState. +// If the handle is destroyed and the RequestedLayerState does not have a parent, +// the LayerLifecycleManager destroys the RequestedLayerState. +// +// Threading: This class is not thread safe, it requires external synchronization. +// +// Typical usage: Input states (new layers, transactions, destroyed layer handles) +// are collected in the background passed into the LayerLifecycleManager to update +// layer lifecycle and layer state at start of composition. +class LayerLifecycleManager { +public: + // External state changes should be updated in the following order: + void addLayers(std::vector<std::unique_ptr<RequestedLayerState>>); + void applyTransactions(const std::vector<TransactionState>&); + void onHandlesDestroyed(const std::vector<uint32_t>&); + + // Destroys RequestedLayerStates that are marked to be destroyed. Invokes all + // ILifecycleListener callbacks and clears any change flags from previous state + // updates. This function should be called outside the hot path since it's not + // critical to composition. + void commitChanges(); + + class ILifecycleListener { + public: + virtual ~ILifecycleListener() = default; + // Called on commitChanges when a layer is added. The callback includes + // the layer state the client was created with as well as any state updates + // until changes were committed. + virtual void onLayerAdded(const RequestedLayerState&) = 0; + // Called on commitChanges when a layer has been destroyed. The callback + // includes the final state before the layer was destroyed. + virtual void onLayerDestroyed(const RequestedLayerState&) = 0; + }; + void addLifecycleListener(std::shared_ptr<ILifecycleListener>); + void removeLifecycleListener(std::shared_ptr<ILifecycleListener>); + const std::vector<std::unique_ptr<RequestedLayerState>>& getLayers() const; + const std::vector<std::unique_ptr<RequestedLayerState>>& getDestroyedLayers() const; + const ftl::Flags<RequestedLayerState::Changes> getGlobalChanges() const; + +private: + friend class LayerLifecycleManagerTest; + friend class HierarchyBuilderTest; + friend class android::SurfaceFlinger; + + RequestedLayerState* getLayerFromId(uint32_t); + std::vector<uint32_t>* getLinkedLayersFromId(uint32_t); + void linkLayer(uint32_t layerId, uint32_t layerToLink); + void unlinkLayer(uint32_t& inOutLayerId, uint32_t linkedLayer); + + struct References { + // Lifetime tied to mLayers + RequestedLayerState& owner; + std::vector<uint32_t> references; + std::string getDebugString() const; + }; + std::unordered_map<uint32_t, References> mIdToLayer; + // Listeners are invoked once changes are committed. + std::vector<std::shared_ptr<ILifecycleListener>> mListeners; + + // Aggregation of changes since last commit. + ftl::Flags<RequestedLayerState::Changes> mGlobalChanges; + std::vector<std::unique_ptr<RequestedLayerState>> mLayers; + // Layers pending destruction. Layers will be destroyed once changes are committed. + std::vector<std::unique_ptr<RequestedLayerState>> mDestroyedLayers; +}; + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp new file mode 100644 index 0000000000..45058d900f --- /dev/null +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -0,0 +1,358 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FrontEnd/LayerCreationArgs.h" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#undef LOG_TAG +#define LOG_TAG "RequestedLayerState" + +#include <private/android_filesystem_config.h> +#include <sys/types.h> + +#include "Layer.h" +#include "LayerHandle.h" +#include "RequestedLayerState.h" + +namespace android::surfaceflinger::frontend { +using ftl::Flags; +using namespace ftl::flag_operators; + +namespace { +uint32_t getLayerIdFromSurfaceControl(sp<SurfaceControl> surfaceControl) { + if (!surfaceControl) { + return UNASSIGNED_LAYER_ID; + } + + return LayerHandle::getLayerId(surfaceControl->getHandle()); +} + +std::string layerIdToString(uint32_t layerId) { + return layerId == UNASSIGNED_LAYER_ID ? std::to_string(layerId) : "none"; +} + +} // namespace + +RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args) + : id(args.sequence), + name(args.name), + canBeRoot(args.addToRoot), + layerCreationFlags(args.flags), + textureName(args.textureName), + ownerUid(args.ownerUid), + ownerPid(args.ownerPid) { + layerId = static_cast<int32_t>(args.sequence); + changes |= RequestedLayerState::Changes::Created; + metadata.merge(args.metadata); + changes |= RequestedLayerState::Changes::Metadata; + handleAlive = true; + parentId = LayerHandle::getLayerId(args.parentHandle.promote()); + mirrorId = LayerHandle::getLayerId(args.mirrorLayerHandle.promote()); + if (mirrorId != UNASSIGNED_LAYER_ID) { + changes |= RequestedLayerState::Changes::Mirror; + } + + flags = 0; + if (args.flags & ISurfaceComposerClient::eHidden) flags |= layer_state_t::eLayerHidden; + if (args.flags & ISurfaceComposerClient::eOpaque) flags |= layer_state_t::eLayerOpaque; + if (args.flags & ISurfaceComposerClient::eSecure) flags |= layer_state_t::eLayerSecure; + if (args.flags & ISurfaceComposerClient::eSkipScreenshot) { + flags |= layer_state_t::eLayerSkipScreenshot; + } + premultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); + potentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; + protectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; + if (args.flags & ISurfaceComposerClient::eNoColorFill) { + // Set an invalid color so there is no color fill. + // (b/259981098) use an explicit flag instead of relying on invalid values. + color.r = -1.0_hf; + color.g = -1.0_hf; + color.b = -1.0_hf; + } else { + color.rgb = {0.0_hf, 0.0_hf, 0.0_hf}; + } + color.a = 1.0f; + + crop.makeInvalid(); + z = 0; + layerStack = ui::DEFAULT_LAYER_STACK; + transformToDisplayInverse = false; + dataspace = ui::Dataspace::UNKNOWN; + dataspaceRequested = false; + hdrMetadata.validTypes = 0; + surfaceDamageRegion = Region::INVALID_REGION; + cornerRadius = 0.0f; + backgroundBlurRadius = 0; + api = -1; + hasColorTransform = false; + bufferTransform = 0; + requestedTransform.reset(); + bufferData = std::make_shared<BufferData>(); + bufferData->frameNumber = 0; + bufferData->acquireFence = sp<Fence>::make(-1); + acquireFenceTime = std::make_shared<FenceTime>(bufferData->acquireFence); + colorSpaceAgnostic = false; + frameRateSelectionPriority = Layer::PRIORITY_UNSET; + shadowRadius = 0.f; + fixedTransformHint = ui::Transform::ROT_INVALID; + destinationFrame.makeInvalid(); + isTrustedOverlay = false; + dropInputMode = gui::DropInputMode::NONE; + dimmingEnabled = true; + defaultFrameRateCompatibility = + static_cast<int8_t>(scheduler::LayerInfo::FrameRateCompatibility::Default); + dataspace = ui::Dataspace::V0_SRGB; +} + +void RequestedLayerState::merge(const ResolvedComposerState& resolvedComposerState) { + bool oldFlags = flags; + Rect oldBufferSize = getBufferSize(); + const layer_state_t& clientState = resolvedComposerState.state; + + uint64_t clientChanges = what | layer_state_t::diff(clientState); + layer_state_t::merge(clientState); + what = clientChanges; + + if (clientState.what & layer_state_t::eFlagsChanged) { + if ((oldFlags ^ flags) & layer_state_t::eLayerHidden) { + changes |= RequestedLayerState::Changes::Visibility; + } + if ((oldFlags ^ flags) & layer_state_t::eIgnoreDestinationFrame) { + changes |= RequestedLayerState::Changes::Geometry; + } + } + if (clientState.what & layer_state_t::eBufferChanged && oldBufferSize != getBufferSize()) { + changes |= RequestedLayerState::Changes::Geometry; + } + if (clientChanges & layer_state_t::HIERARCHY_CHANGES) + changes |= RequestedLayerState::Changes::Hierarchy; + if (clientChanges & layer_state_t::CONTENT_CHANGES) + changes |= RequestedLayerState::Changes::Content; + if (clientChanges & layer_state_t::GEOMETRY_CHANGES) + changes |= RequestedLayerState::Changes::Geometry; + + if (clientState.what & layer_state_t::eColorTransformChanged) { + static const mat4 identityMatrix = mat4(); + hasColorTransform = colorTransform != identityMatrix; + } + if (clientState.what & layer_state_t::eLayerChanged) { + changes |= RequestedLayerState::Changes::Z; + } + if (clientState.what & layer_state_t::eReparent) { + changes |= RequestedLayerState::Changes::Parent; + parentId = getLayerIdFromSurfaceControl(clientState.parentSurfaceControlForChild); + parentSurfaceControlForChild = nullptr; + } + if (clientState.what & layer_state_t::eRelativeLayerChanged) { + changes |= RequestedLayerState::Changes::RelativeParent; + relativeParentId = getLayerIdFromSurfaceControl(clientState.relativeLayerSurfaceControl); + isRelativeOf = true; + relativeLayerSurfaceControl = nullptr; + } + if ((clientState.what & layer_state_t::eLayerChanged || + (clientState.what & layer_state_t::eReparent && parentId == UNASSIGNED_LAYER_ID)) && + isRelativeOf) { + // clear out relz data + relativeParentId = UNASSIGNED_LAYER_ID; + isRelativeOf = false; + changes |= RequestedLayerState::Changes::RelativeParent; + } + if (clientState.what & layer_state_t::eReparent && parentId == relativeParentId) { + // provide a hint that we are are now a direct child and not a relative child. + changes |= RequestedLayerState::Changes::RelativeParent; + } + if (clientState.what & layer_state_t::eInputInfoChanged) { + wp<IBinder>& touchableRegionCropHandle = + windowInfoHandle->editInfo()->touchableRegionCropHandle; + touchCropId = LayerHandle::getLayerId(touchableRegionCropHandle.promote()); + changes |= RequestedLayerState::Changes::Input; + touchableRegionCropHandle.clear(); + } + if (clientState.what & layer_state_t::eStretchChanged) { + stretchEffect.sanitize(); + } + + if (clientState.what & layer_state_t::eHasListenerCallbacksChanged) { + // TODO(b/238781169) handle callbacks + } + + if (clientState.what & layer_state_t::eBufferChanged) { + externalTexture = resolvedComposerState.externalTexture; + hwcBufferSlot = resolvedComposerState.hwcBufferSlot; + } + + if (clientState.what & layer_state_t::ePositionChanged) { + requestedTransform.set(x, y); + } + + if (clientState.what & layer_state_t::eMatrixChanged) { + requestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); + } +} + +ui::Transform RequestedLayerState::getTransform() const { + if ((flags & layer_state_t::eIgnoreDestinationFrame) || destinationFrame.isEmpty()) { + // If destination frame is not set, use the requested transform set via + // Transaction::setPosition and Transaction::setMatrix. + return requestedTransform; + } + + Rect destRect = destinationFrame; + int32_t destW = destRect.width(); + int32_t destH = destRect.height(); + if (destRect.left < 0) { + destRect.left = 0; + destRect.right = destW; + } + if (destRect.top < 0) { + destRect.top = 0; + destRect.bottom = destH; + } + + if (!externalTexture) { + ui::Transform transform; + transform.set(static_cast<float>(destRect.left), static_cast<float>(destRect.top)); + return transform; + } + + uint32_t bufferWidth = externalTexture->getWidth(); + uint32_t bufferHeight = externalTexture->getHeight(); + // Undo any transformations on the buffer. + if (bufferTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + // TODO(b/238781169) remove dep + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (transformToDisplayInverse) { + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufferWidth, bufferHeight); + } + } + + float sx = static_cast<float>(destW) / static_cast<float>(bufferWidth); + float sy = static_cast<float>(destH) / static_cast<float>(bufferHeight); + ui::Transform transform; + transform.set(sx, 0, 0, sy); + transform.set(static_cast<float>(destRect.left), static_cast<float>(destRect.top)); + return transform; +} + +std::string RequestedLayerState::getDebugString() const { + return "[" + std::to_string(id) + "]" + name + ",parent=" + layerIdToString(parentId) + + ",relativeParent=" + layerIdToString(relativeParentId) + + ",isRelativeOf=" + std::to_string(isRelativeOf) + + ",mirrorId=" + layerIdToString(mirrorId) + + ",handleAlive=" + std::to_string(handleAlive); +} + +std::string RequestedLayerState::getDebugStringShort() const { + return "[" + std::to_string(id) + "]" + name; +} + +bool RequestedLayerState::canBeDestroyed() const { + return !handleAlive && parentId == UNASSIGNED_LAYER_ID; +} +bool RequestedLayerState::isRoot() const { + return canBeRoot && parentId == UNASSIGNED_LAYER_ID; +} +bool RequestedLayerState::isHiddenByPolicy() const { + return (flags & layer_state_t::eLayerHidden) == layer_state_t::eLayerHidden; +}; +half4 RequestedLayerState::getColor() const { + if ((sidebandStream != nullptr) || (externalTexture != nullptr)) { + return {0._hf, 0._hf, 0._hf, color.a}; + } + return color; +} +Rect RequestedLayerState::getBufferSize() const { + // for buffer state layers we use the display frame size as the buffer size. + if (!externalTexture) { + return Rect::INVALID_RECT; + } + + uint32_t bufWidth = externalTexture->getWidth(); + uint32_t bufHeight = externalTexture->getHeight(); + + // Undo any transformations on the buffer and return the result. + if (bufferTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + + if (transformToDisplayInverse) { + // TODO(b/238781169) pass in display metrics (would be useful for input info as well + uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); + if (invTransform & ui::Transform::ROT_90) { + std::swap(bufWidth, bufHeight); + } + } + + return Rect(0, 0, static_cast<int32_t>(bufWidth), static_cast<int32_t>(bufHeight)); +} + +Rect RequestedLayerState::getCroppedBufferSize() const { + Rect size = getBufferSize(); + if (!crop.isEmpty() && size.isValid()) { + size.intersect(crop, &size); + } else if (!crop.isEmpty()) { + size = crop; + } + return size; +} + +Rect RequestedLayerState::getBufferCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) + if (!bufferCrop.isEmpty()) { + // if the buffer crop is defined, we use that + return bufferCrop; + } else if (externalTexture != nullptr) { + // otherwise we use the whole buffer + return externalTexture->getBounds(); + } else { + // if we don't have a buffer yet, we use an empty/invalid crop + return Rect(); + } +} + +aidl::android::hardware::graphics::composer3::Composition RequestedLayerState::getCompositionType() + const { + using aidl::android::hardware::graphics::composer3::Composition; + // TODO(b/238781169) check about sidestream ready flag + if (sidebandStream.get()) { + return Composition::SIDEBAND; + } + if (!externalTexture) { + return Composition::SOLID_COLOR; + } + if (flags & layer_state_t::eLayerIsDisplayDecoration) { + return Composition::DISPLAY_DECORATION; + } + if (potentialCursor) { + return Composition::CURSOR; + } + return Composition::DEVICE; +} + +Rect RequestedLayerState::reduce(const Rect& win, const Region& exclude) { + if (CC_LIKELY(exclude.isEmpty())) { + return win; + } + if (exclude.isRect()) { + return win.reduce(exclude.getBounds()); + } + return Region(win).subtract(exclude).getBounds(); +} + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h new file mode 100644 index 0000000000..0ddf5e2895 --- /dev/null +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h @@ -0,0 +1,102 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <aidl/android/hardware/graphics/composer3/Composition.h> +#include <ftl/flags.h> +#include <gui/LayerState.h> +#include <renderengine/ExternalTexture.h> + +#include "LayerCreationArgs.h" +#include "TransactionState.h" + +namespace android::surfaceflinger::frontend { + +// Stores client requested states for a layer. +// This struct does not store any other states or states pertaining to +// other layers. Links to other layers that are part of the client +// requested state such as parent are translated to layer id so +// we can avoid extending the lifetime of layer handles. +struct RequestedLayerState : layer_state_t { + // Changes in state after merging with new state. This includes additional state + // changes found in layer_state_t::what. + enum class Changes : uint32_t { + Created = 1u << 0, + Destroyed = 1u << 1, + Hierarchy = 1u << 2, + Geometry = 1u << 3, + Content = 1u << 4, + Input = 1u << 5, + Z = 1u << 6, + Mirror = 1u << 7, + Parent = 1u << 8, + RelativeParent = 1u << 9, + Metadata = 1u << 10, + Visibility = 1u << 11, + }; + static Rect reduce(const Rect& win, const Region& exclude); + RequestedLayerState(const LayerCreationArgs&); + void merge(const ResolvedComposerState&); + ui::Transform getTransform() const; + bool canBeDestroyed() const; + bool isRoot() const; + bool isHiddenByPolicy() const; + half4 getColor() const; + Rect getBufferSize() const; + Rect getCroppedBufferSize() const; + Rect getBufferCrop() const; + std::string getDebugString() const; + std::string getDebugStringShort() const; + aidl::android::hardware::graphics::composer3::Composition getCompositionType() const; + + // Layer serial number. This gives layers an explicit ordering, so we + // have a stable sort order when their layer stack and Z-order are + // the same. + const uint32_t id; + const std::string name; + const bool canBeRoot = false; + const uint32_t layerCreationFlags; + const uint32_t textureName; + // The owner of the layer. If created from a non system process, it will be the calling uid. + // If created from a system process, the value can be passed in. + const uid_t ownerUid; + // The owner pid of the layer. If created from a non system process, it will be the calling pid. + // If created from a system process, the value can be passed in. + const pid_t ownerPid; + bool dataspaceRequested; + bool hasColorTransform; + bool premultipliedAlpha{true}; + // This layer can be a cursor on some displays. + bool potentialCursor{false}; + bool protectedByApp{false}; // application requires protected path to external sink + ui::Transform requestedTransform; + std::shared_ptr<FenceTime> acquireFenceTime; + std::shared_ptr<renderengine::ExternalTexture> externalTexture; + int hwcBufferSlot = 0; + + // book keeping states + bool handleAlive = true; + bool isRelativeOf = false; + uint32_t parentId = UNASSIGNED_LAYER_ID; + uint32_t relativeParentId = UNASSIGNED_LAYER_ID; + uint32_t mirrorId = UNASSIGNED_LAYER_ID; + uint32_t touchCropId = UNASSIGNED_LAYER_ID; + uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID; + ftl::Flags<RequestedLayerState::Changes> changes; +}; + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/SwapErase.h b/services/surfaceflinger/FrontEnd/SwapErase.h new file mode 100644 index 0000000000..f672f998d9 --- /dev/null +++ b/services/surfaceflinger/FrontEnd/SwapErase.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <vector> + +namespace android::surfaceflinger::frontend { +// Erases the first element in vec that matches value. This is a more optimal way to +// remove an element from a vector that avoids relocating all the elements after the one +// that is erased. +template <typename T> +void swapErase(std::vector<T>& vec, const T& value) { + auto it = std::find(vec.begin(), vec.end(), value); + if (it != vec.end()) { + std::iter_swap(it, vec.end() - 1); + vec.erase(vec.end() - 1); + } +} + +// Similar to swapErase(std::vector<T>& vec, const T& value) but erases the first element +// that returns true for predicate. +template <typename T, class P> +void swapErase(std::vector<T>& vec, P predicate) { + auto it = std::find_if(vec.begin(), vec.end(), predicate); + if (it != vec.end()) { + std::iter_swap(it, vec.end() - 1); + vec.erase(vec.end() - 1); + } +} + +} // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 7669bab487..f743896c03 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -83,6 +83,7 @@ class SurfaceFrame; } // namespace frametimeline class Layer : public virtual RefBase { +public: // The following constants represent priority of the window. SF uses this information when // deciding which window has a priority when deciding about the refresh rate of the screen. // Priority 0 is considered the highest priority. -1 means that the priority is unset. @@ -94,7 +95,6 @@ class Layer : public virtual RefBase { // Windows that are not in focus, but voted for a specific mode ID. static constexpr int32_t PRIORITY_NOT_FOCUSED_WITH_MODE = 2; -public: enum { // flags for doTransaction() eDontUpdateGeometryState = 0x00000001, eVisibleRegion = 0x00000002, diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d88da4da4a..26c0d8e158 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -92,6 +92,7 @@ cc_test { "LayerHistoryTest.cpp", "LayerInfoTest.cpp", "LayerMetadataTest.cpp", + "LayerLifecycleManagerTest.cpp", "LayerTest.cpp", "LayerTestUtils.cpp", "MessageQueueTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp new file mode 100644 index 0000000000..89440a689c --- /dev/null +++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp @@ -0,0 +1,453 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include "FrontEnd/LayerHandle.h" +#include "FrontEnd/LayerLifecycleManager.h" +#include "Layer.h" +#include "gui/SurfaceComposerClient.h" + +using namespace android::surfaceflinger; + +namespace android::surfaceflinger::frontend { + +namespace { +LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent, wp<IBinder> mirror) { + LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id)); + args.addToRoot = canBeRoot; + args.parentHandle = parent; + args.mirrorLayerHandle = mirror; + return args; +} +} // namespace + +// To run test: +/** + mp :libsurfaceflinger_unittest && adb sync; adb shell \ + /data/nativetest/libsurfaceflinger_unittest/libsurfaceflinger_unittest \ + --gtest_filter="LayerLifecycleManagerTest.*" --gtest_repeat=100 \ + --gtest_shuffle \ + --gtest_brief=1 +*/ +class ExpectLayerLifecycleListener : public LayerLifecycleManager::ILifecycleListener { +public: + void onLayerAdded(const RequestedLayerState& layer) override { + mActualLayersAdded.emplace(layer.id); + }; + void onLayerDestroyed(const RequestedLayerState& layer) override { + mActualLayersDestroyed.emplace(layer.id); + }; + + void expectLayersAdded(const std::unordered_set<uint32_t>& expectedLayersAdded) { + EXPECT_EQ(expectedLayersAdded, mActualLayersAdded); + mActualLayersAdded.clear(); + } + void expectLayersDestroyed(const std::unordered_set<uint32_t>& expectedLayersDestroyed) { + EXPECT_EQ(expectedLayersDestroyed, mActualLayersDestroyed); + mActualLayersDestroyed.clear(); + } + + std::unordered_set<uint32_t> mActualLayersAdded; + std::unordered_set<uint32_t> mActualLayersDestroyed; +}; + +class LayerLifecycleManagerTest : public testing::Test { +protected: + std::unique_ptr<RequestedLayerState> rootLayer(uint32_t id) { + return std::make_unique<RequestedLayerState>( + createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr)); + } + + std::unique_ptr<RequestedLayerState> childLayer(uint32_t id, uint32_t parentId) { + mHandles[parentId] = sp<LayerHandle>::make(parentId); + return std::make_unique<RequestedLayerState>(createArgs(/*id=*/id, /*canBeRoot=*/false, + /*parent=*/mHandles[parentId], + /*mirror=*/nullptr)); + } + + TransactionState reparentLayer(uint32_t id, uint32_t newParentId) { + TransactionState transaction; + transaction.states.push_back({}); + + if (newParentId == UNASSIGNED_LAYER_ID) { + transaction.states.front().state.parentSurfaceControlForChild = nullptr; + } else { + transaction.states.front().state.parentSurfaceControlForChild = + sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), + sp<LayerHandle>::make(newParentId), + static_cast<int32_t>(newParentId), "Test"); + } + transaction.states.front().state.what = layer_state_t::eReparent; + transaction.states.front().state.surface = sp<LayerHandle>::make(id); + return transaction; + } + + TransactionState setLayer(uint32_t id, int32_t z) { + TransactionState transaction; + transaction.states.push_back({}); + transaction.states.front().state.z = z; + transaction.states.front().state.what = layer_state_t::eLayerChanged; + transaction.states.front().state.surface = sp<LayerHandle>::make(id); + return transaction; + } + + TransactionState makeRelative(uint32_t id, uint32_t relativeParentId) { + TransactionState transaction; + transaction.states.push_back({}); + + if (relativeParentId == UNASSIGNED_LAYER_ID) { + transaction.states.front().state.relativeLayerSurfaceControl = nullptr; + } else { + transaction.states.front().state.relativeLayerSurfaceControl = + sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), + sp<LayerHandle>::make(relativeParentId), + static_cast<int32_t>(relativeParentId), "Test"); + } + transaction.states.front().state.what = layer_state_t::eRelativeLayerChanged; + transaction.states.front().state.surface = sp<LayerHandle>::make(id); + return transaction; + } + + RequestedLayerState* getRequestedLayerState(LayerLifecycleManager& lifecycleManager, + uint32_t layerId) { + return lifecycleManager.getLayerFromId(layerId); + } + + std::unordered_map<uint32_t, sp<LayerHandle>> mHandles; +}; + +TEST_F(LayerLifecycleManagerTest, addLayers) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(rootLayer(3)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.onHandlesDestroyed({1, 2, 3}); + EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + listener->expectLayersAdded({1, 2, 3}); + listener->expectLayersDestroyed({1, 2, 3}); +} + +TEST_F(LayerLifecycleManagerTest, updateLayerStates) { + LayerLifecycleManager lifecycleManager; + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + lifecycleManager.addLayers(std::move(layers)); + + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.z = 2; + transactions.back().states.front().state.what = layer_state_t::eLayerChanged; + sp<LayerHandle> handle = sp<LayerHandle>::make(1u); + transactions.back().states.front().state.surface = handle; + lifecycleManager.applyTransactions(transactions); + transactions.clear(); + + auto& managedLayers = lifecycleManager.getLayers(); + ASSERT_EQ(managedLayers.size(), 1u); + + EXPECT_EQ(managedLayers.front()->z, 2); + EXPECT_TRUE(managedLayers.front()->changes.test(RequestedLayerState::Changes::Z)); + + EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + ASSERT_EQ(managedLayers.size(), 1u); + EXPECT_FALSE(managedLayers.front()->changes.test(RequestedLayerState::Changes::Z)); + + // apply transactions that do not affect the hierarchy + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.backgroundBlurRadius = 22; + transactions.back().states.front().state.what = layer_state_t::eBackgroundBlurRadiusChanged; + transactions.back().states.front().state.surface = handle; + lifecycleManager.applyTransactions(transactions); + EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + EXPECT_FALSE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + EXPECT_EQ(managedLayers.front()->backgroundBlurRadius, 22u); +} + +TEST_F(LayerLifecycleManagerTest, layerWithoutHandleIsDestroyed) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.onHandlesDestroyed({1}); + lifecycleManager.commitChanges(); + + SCOPED_TRACE("layerWithoutHandleIsDestroyed"); + listener->expectLayersAdded({1, 2}); + listener->expectLayersDestroyed({1}); +} + +TEST_F(LayerLifecycleManagerTest, rootLayerWithoutHandleIsDestroyed) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.onHandlesDestroyed({1}); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2}); + listener->expectLayersDestroyed({1}); +} + +TEST_F(LayerLifecycleManagerTest, offscreenLayerIsDestroyed) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)}); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({}); + + lifecycleManager.onHandlesDestroyed({3}); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({3}); +} + +TEST_F(LayerLifecycleManagerTest, offscreenChildLayerWithHandleIsNotDestroyed) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + layers.emplace_back(childLayer(4, /*parent*/ 3)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3, 4}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)}); + lifecycleManager.onHandlesDestroyed({3}); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({3}); +} + +TEST_F(LayerLifecycleManagerTest, offscreenChildLayerWithoutHandleIsDestroyed) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + layers.emplace_back(childLayer(4, /*parent*/ 3)); + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3, 4}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({reparentLayer(3, UNASSIGNED_LAYER_ID)}); + lifecycleManager.onHandlesDestroyed({3, 4}); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({3, 4}); +} + +TEST_F(LayerLifecycleManagerTest, reparentingDoesNotAffectRelativeZ) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + layers.emplace_back(childLayer(4, /*parent*/ 3)); + + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3, 4}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({makeRelative(4, 1)}); + EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + lifecycleManager.applyTransactions({reparentLayer(4, 2)}); + EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({}); +} + +TEST_F(LayerLifecycleManagerTest, reparentingToNullRemovesRelativeZ) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + layers.emplace_back(childLayer(4, /*parent*/ 3)); + + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3, 4}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({makeRelative(4, 1)}); + EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + lifecycleManager.applyTransactions({reparentLayer(4, UNASSIGNED_LAYER_ID)}); + EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({}); +} + +TEST_F(LayerLifecycleManagerTest, setZRemovesRelativeZ) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + layers.emplace_back(rootLayer(2)); + layers.emplace_back(childLayer(3, /*parent*/ 2)); + layers.emplace_back(childLayer(4, /*parent*/ 3)); + + lifecycleManager.addLayers(std::move(layers)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2, 3, 4}); + listener->expectLayersDestroyed({}); + + lifecycleManager.applyTransactions({makeRelative(4, 1)}); + EXPECT_TRUE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + lifecycleManager.applyTransactions({setLayer(4, 1)}); + EXPECT_FALSE(getRequestedLayerState(lifecycleManager, 4)->isRelativeOf); + + lifecycleManager.commitChanges(); + listener->expectLayersAdded({}); + listener->expectLayersDestroyed({}); +} + +TEST_F(LayerLifecycleManagerTest, canAddBackgroundLayer) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + lifecycleManager.addLayers(std::move(layers)); + + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; + sp<LayerHandle> handle = sp<LayerHandle>::make(1u); + transactions.back().states.front().state.surface = handle; + lifecycleManager.applyTransactions(transactions); + + auto& managedLayers = lifecycleManager.getLayers(); + ASSERT_EQ(managedLayers.size(), 2u); + + EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2}); + listener->expectLayersDestroyed({}); + EXPECT_EQ(getRequestedLayerState(lifecycleManager, 2)->color.a, 0.5_hf); +} + +TEST_F(LayerLifecycleManagerTest, canDestroyBackgroundLayer) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + lifecycleManager.addLayers(std::move(layers)); + + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; + sp<LayerHandle> handle = sp<LayerHandle>::make(1u); + transactions.back().states.front().state.surface = handle; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.bgColorAlpha = 0; + transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; + transactions.back().states.front().state.surface = handle; + + lifecycleManager.applyTransactions(transactions); + + ASSERT_EQ(lifecycleManager.getLayers().size(), 1u); + ASSERT_EQ(lifecycleManager.getDestroyedLayers().size(), 1u); + + EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2}); + listener->expectLayersDestroyed({2}); +} + +TEST_F(LayerLifecycleManagerTest, onParentDestroyDestroysBackgroundLayer) { + LayerLifecycleManager lifecycleManager; + auto listener = std::make_shared<ExpectLayerLifecycleListener>(); + lifecycleManager.addLifecycleListener(listener); + + std::vector<std::unique_ptr<RequestedLayerState>> layers; + layers.emplace_back(rootLayer(1)); + lifecycleManager.addLayers(std::move(layers)); + + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.front().state.bgColorAlpha = 0.5; + transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged; + sp<LayerHandle> handle = sp<LayerHandle>::make(1u); + transactions.back().states.front().state.surface = handle; + transactions.emplace_back(); + lifecycleManager.applyTransactions(transactions); + lifecycleManager.onHandlesDestroyed({1}); + + ASSERT_EQ(lifecycleManager.getLayers().size(), 0u); + ASSERT_EQ(lifecycleManager.getDestroyedLayers().size(), 2u); + + EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)); + lifecycleManager.commitChanges(); + listener->expectLayersAdded({1, 2}); + listener->expectLayersDestroyed({1, 2}); +} + +} // namespace android::surfaceflinger::frontend |