SF: Clean up HWC2::Layer ownership
Changes the HWC2::Display::createLayer() call to return a shared_ptr
instead of a bare pointer. Also if the HWC2::Display is disconnected,
instead of directly destroying the HWC2::Layers associated with the
display, a new call is made to clear the display information from the
layer. For safety, checks are added to take an early out if the display
information isn't set for any call where it is used.
The CompositionEngine code was already creating a shared_ptr for the
createLayer call, and expecting the pointer to be valid until it
released it via destroyLayer.
However a hotplug disconnect could leave the CompositionEngine code
holding an invalid pointer until the next display refresh, and it could
lead to bad memory accesses if the pointer was dereferenced.
CompositionEngine itself did not do so -- it released its ownership of
the layer (and the associated display) without accessing them. This
seems to have only affected "dumpsys SurfaceFlinger", if it happened to
be executed after the disconnect, and before another refresh, and only
because it tried to print out the HWC layer id.
Bug: 181061001
Test: libsurfaceflinger_unittest
Test: libcompositionengine_test
Test: dumpsys SurfaceFlinger # after hotplug event
Change-Id: I508d6aa8ef7a6af848dd54198408d5f311175070
Merged-In: I508d6aa8ef7a6af848dd54198408d5f311175070
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e7bf286..fae95e7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android-base/expected.h>
#include <gui/HdrMetadata.h>
#include <math/mat4.h>
#include <ui/HdrCapabilities.h>
@@ -84,10 +85,11 @@
virtual void setConnected(bool connected) = 0; // For use by Device only
virtual const std::unordered_set<hal::DisplayCapability>& getCapabilities() const = 0;
virtual bool isVsyncPeriodSwitchSupported() const = 0;
+ virtual void onLayerDestroyed(hal::HWLayerId layerId) = 0;
[[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0;
- [[clang::warn_unused_result]] virtual hal::Error createLayer(Layer** outLayer) = 0;
- [[clang::warn_unused_result]] virtual hal::Error destroyLayer(Layer* layer) = 0;
+ [[clang::warn_unused_result]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
+ createLayer() = 0;
[[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes(
std::unordered_map<Layer*, hal::Composition>* outTypes) = 0;
[[clang::warn_unused_result]] virtual hal::Error getColorModes(
@@ -152,6 +154,8 @@
namespace impl {
+class Layer;
+
class Display : public HWC2::Display {
public:
Display(android::Hwc2::Composer&, const std::unordered_set<hal::Capability>&, hal::HWDisplayId,
@@ -160,10 +164,9 @@
// Required by HWC2
hal::Error acceptChanges() override;
- hal::Error createLayer(Layer** outLayer) override;
- hal::Error destroyLayer(Layer*) override;
+ base::expected<std::shared_ptr<HWC2::Layer>, hal::Error> createLayer() override;
hal::Error getChangedCompositionTypes(
- std::unordered_map<Layer*, hal::Composition>* outTypes) override;
+ std::unordered_map<HWC2::Layer*, hal::Composition>* outTypes) override;
hal::Error getColorModes(std::vector<hal::ColorMode>* outModes) const override;
// Returns a bitmask which contains HdrMetadata::Type::*.
int32_t getSupportedPerFrameMetadata() const override;
@@ -174,7 +177,7 @@
hal::Error getName(std::string* outName) const override;
hal::Error getRequests(
hal::DisplayRequest* outDisplayRequests,
- std::unordered_map<Layer*, hal::LayerRequest>* outLayerRequests) override;
+ std::unordered_map<HWC2::Layer*, hal::LayerRequest>* outLayerRequests) override;
hal::Error getConnectionType(ui::DisplayConnectionType*) const override;
hal::Error supportsDoze(bool* outSupport) const override;
hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override;
@@ -185,8 +188,8 @@
uint64_t maxFrames) const override;
hal::Error getDisplayedContentSample(uint64_t maxFrames, uint64_t timestamp,
android::DisplayedFrameStats* outStats) const override;
- hal::Error getReleaseFences(
- std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const override;
+ hal::Error getReleaseFences(std::unordered_map<HWC2::Layer*, android::sp<android::Fence>>*
+ outFences) const override;
hal::Error present(android::sp<android::Fence>* outPresentFence) override;
hal::Error setClientTarget(uint32_t slot, const android::sp<android::GraphicBuffer>& target,
const android::sp<android::Fence>& acquireFence,
@@ -218,13 +221,14 @@
const std::unordered_set<hal::DisplayCapability>& getCapabilities() const override {
return mDisplayCapabilities;
};
- virtual bool isVsyncPeriodSwitchSupported() const override;
+ bool isVsyncPeriodSwitchSupported() const override;
+ void onLayerDestroyed(hal::HWLayerId layerId) override;
private:
// This may fail (and return a null pointer) if no layer with this ID exists
// on this display
- Layer* getLayerById(hal::HWLayerId) const;
+ std::shared_ptr<HWC2::Layer> getLayerById(hal::HWLayerId id) const;
friend android::TestableSurfaceFlinger;
@@ -240,7 +244,8 @@
hal::DisplayType mType;
bool mIsConnected = false;
- std::unordered_map<hal::HWLayerId, std::unique_ptr<Layer>> mLayers;
+ using Layers = std::unordered_map<hal::HWLayerId, std::weak_ptr<HWC2::impl::Layer>>;
+ Layers mLayers;
std::once_flag mDisplayCapabilityQueryFlag;
std::unordered_set<hal::DisplayCapability> mDisplayCapabilities;
@@ -295,10 +300,12 @@
class Layer : public HWC2::Layer {
public:
Layer(android::Hwc2::Composer& composer,
- const std::unordered_set<hal::Capability>& capabilities, hal::HWDisplayId displayId,
+ const std::unordered_set<hal::Capability>& capabilities, HWC2::Display& display,
hal::HWLayerId layerId);
~Layer() override;
+ void onOwningDisplayDestroyed();
+
hal::HWLayerId getId() const override { return mId; }
hal::Error setCursorPosition(int32_t x, int32_t y) override;
@@ -334,7 +341,7 @@
android::Hwc2::Composer& mComposer;
const std::unordered_set<hal::Capability>& mCapabilities;
- hal::HWDisplayId mDisplayId;
+ HWC2::Display* mDisplay;
hal::HWLayerId mId;
// Cached HWC2 data, to ensure the same commands aren't sent to the HWC