Merge "Add tracing for InputConsumer lifetime" into main
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 9791212..8d5d1e4 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -195,7 +195,7 @@
EXPECT_EQ(hasFocus, focusEvent->getHasFocus());
}
- void expectTap(int x, int y) {
+ void expectTap(float x, float y) {
InputEvent* ev = consumeEvent();
ASSERT_NE(ev, nullptr);
ASSERT_EQ(InputEventType::MOTION, ev->getType());
@@ -268,6 +268,11 @@
EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS);
}
+ void assertNoEvent() {
+ InputEvent* event = consumeEvent(/*timeout=*/100ms);
+ ASSERT_EQ(event, nullptr) << "Expected no event, but got " << *event;
+ }
+
virtual ~InputSurface() {
if (mClientChannel) {
mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken());
@@ -937,9 +942,7 @@
surface->showAt(100, 100);
injectTap(101, 101);
-
- EXPECT_NE(surface->consumeEvent(), nullptr);
- EXPECT_NE(surface->consumeEvent(), nullptr);
+ surface->expectTap(1, 1);
surface->requestFocus();
surface->assertFocusChange(true);
@@ -956,9 +959,7 @@
surface->showAt(100, 100);
injectTap(101, 101);
-
- EXPECT_NE(surface->consumeEvent(), nullptr);
- EXPECT_NE(surface->consumeEvent(), nullptr);
+ surface->expectTap(.5, .5);
surface->requestFocus();
surface->assertFocusChange(true);
@@ -977,12 +978,12 @@
obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
@@ -998,12 +999,12 @@
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
@@ -1020,12 +1021,12 @@
injectTap(101, 101);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
@@ -1042,12 +1043,12 @@
injectTap(111, 111);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(InputSurfacesTest, ignore_touch_region_with_zero_sized_blast) {
@@ -1071,13 +1072,12 @@
surface->showAt(100, 100);
injectTap(101, 101);
-
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus();
surface->assertFocusChange(true);
injectKey(AKEYCODE_V);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(InputSurfacesTest, layer_with_valid_crop_can_be_focused) {
@@ -1112,7 +1112,7 @@
// Does not receive events outside its crop
injectTap(26, 26);
- EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
+ containerSurface->assertNoEvent();
}
/**
@@ -1137,7 +1137,7 @@
// Does not receive events outside parent bounds
injectTap(31, 31);
- EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
+ containerSurface->assertNoEvent();
}
/**
@@ -1163,7 +1163,7 @@
// Does not receive events outside crop layer bounds
injectTap(21, 21);
injectTap(71, 71);
- EXPECT_EQ(containerSurface->consumeEvent(/*timeout=*/100ms), nullptr);
+ containerSurface->assertNoEvent();
}
TEST_F(InputSurfacesTest, child_container_with_no_input_channel_blocks_parent) {
@@ -1180,7 +1180,7 @@
[&](auto &t, auto &sc) { t.reparent(sc, parent->mSurfaceControl); });
injectTap(101, 101);
- EXPECT_EQ(parent->consumeEvent(/*timeout=*/100ms), nullptr);
+ parent->assertNoEvent();
}
class MultiDisplayTests : public InputSurfacesTest {
@@ -1229,7 +1229,7 @@
// Touches should be dropped if the layer is on an invalid display.
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
// However, we still let the window be focused and receive keys.
surface->requestFocus(layerStack.id);
@@ -1267,12 +1267,12 @@
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
surface->requestFocus(layerStack.id);
surface->assertFocusChange(true);
injectKeyOnDisplay(AKEYCODE_V, layerStack.id);
- EXPECT_EQ(surface->consumeEvent(/*timeout=*/100ms), nullptr);
+ surface->assertNoEvent();
}
TEST_F(MultiDisplayTests, dont_drop_input_for_secure_layer_on_secure_display) {
@@ -1292,8 +1292,7 @@
surface->showAt(100, 100);
injectTapOnDisplay(101, 101, layerStack.id);
- EXPECT_NE(surface->consumeEvent(), nullptr);
- EXPECT_NE(surface->consumeEvent(), nullptr);
+ surface->expectTap(1, 1);
surface->requestFocus(layerStack.id);
surface->assertFocusChange(true);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index e2d17ee..86bcf20 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -143,7 +143,7 @@
compositionengine::OutputLayer* getBlurLayer() const;
- bool hasUnsupportedDataspace() const;
+ bool hasKnownColorShift() const;
bool hasProtectedLayers() const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index dc3821c..5e3e3d8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -74,6 +74,7 @@
BlurRegions = 1u << 18,
HasProtectedContent = 1u << 19,
CachingHint = 1u << 20,
+ DimmingEnabled = 1u << 21,
};
// clang-format on
@@ -248,6 +249,10 @@
ui::Dataspace getDataspace() const { return mOutputDataspace.get(); }
+ hardware::graphics::composer::hal::PixelFormat getPixelFormat() const {
+ return mPixelFormat.get();
+ }
+
float getHdrSdrRatio() const {
return getOutputLayer()->getLayerFE().getCompositionState()->currentHdrSdrRatio;
};
@@ -258,6 +263,8 @@
gui::CachingHint getCachingHint() const { return mCachingHint.get(); }
+ bool isDimmingEnabled() const { return mIsDimmingEnabled.get(); }
+
float getFps() const { return getOutputLayer()->getLayerFE().getCompositionState()->fps; }
void dump(std::string& result) const;
@@ -498,7 +505,10 @@
return std::vector<std::string>{toString(cachingHint)};
}};
- static const constexpr size_t kNumNonUniqueFields = 19;
+ OutputLayerState<bool, LayerStateField::DimmingEnabled> mIsDimmingEnabled{
+ [](auto layer) { return layer->getLayerFE().getCompositionState()->dimmingEnabled; }};
+
+ static const constexpr size_t kNumNonUniqueFields = 20;
std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
std::array<const StateInterface*, kNumNonUniqueFields> constFields =
@@ -516,7 +526,7 @@
&mAlpha, &mLayerMetadata, &mVisibleRegion, &mOutputDataspace,
&mPixelFormat, &mColorTransform, &mCompositionType, &mSidebandStream,
&mBuffer, &mSolidColor, &mBackgroundBlurRadius, &mBlurRegions,
- &mFrameNumber, &mIsProtected, &mCachingHint};
+ &mFrameNumber, &mIsProtected, &mCachingHint, &mIsDimmingEnabled};
}
};
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 1f53588..ea9442d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -27,8 +27,7 @@
#include <renderengine/DisplaySettings.h>
#include <renderengine/RenderEngine.h>
#include <ui/DebugUtils.h>
-#include <utils/Trace.h>
-
+#include <ui/HdrRenderTypeUtils.h>
#include <utils/Trace.h>
namespace android::compositionengine::impl::planner {
@@ -306,7 +305,7 @@
return false;
}
- if (hasUnsupportedDataspace()) {
+ if (hasKnownColorShift()) {
return false;
}
@@ -366,12 +365,21 @@
return mBlurLayer ? mBlurLayer->getOutputLayer() : nullptr;
}
-bool CachedSet::hasUnsupportedDataspace() const {
+bool CachedSet::hasKnownColorShift() const {
return std::any_of(mLayers.cbegin(), mLayers.cend(), [](const Layer& layer) {
auto dataspace = layer.getState()->getDataspace();
- const auto transfer = static_cast<ui::Dataspace>(dataspace & ui::Dataspace::TRANSFER_MASK);
- if (transfer == ui::Dataspace::TRANSFER_ST2084 || transfer == ui::Dataspace::TRANSFER_HLG) {
- // Skip HDR.
+
+ // Layers are never dimmed when rendering a cached set, meaning that we may ask HWC to
+ // dim a cached set. But this means that we can never cache any HDR layers so that we
+ // don't accidentally dim those layers.
+ const auto hdrType = getHdrRenderType(dataspace, layer.getState()->getPixelFormat(),
+ layer.getState()->getHdrSdrRatio());
+ if (hdrType != HdrRenderType::SDR) {
+ return true;
+ }
+
+ // Layers that have dimming disabled pretend that they're HDR.
+ if (!layer.getState()->isDimmingEnabled()) {
return true;
}
@@ -380,10 +388,6 @@
// to avoid flickering/color differences.
return true;
}
- // TODO(b/274804887): temp fix of overdimming issue, skip caching if hsdr/sdr ratio > 1.01f
- if (layer.getState()->getHdrSdrRatio() > 1.01f) {
- return true;
- }
return false;
});
}
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 0a5c43a..4bafed2 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -439,7 +439,7 @@
if (!layerDeniedFromCaching && layerIsInactive &&
(firstLayer || runHasFirstLayer || !layerHasBlur) &&
- !currentSet->hasUnsupportedDataspace()) {
+ !currentSet->hasKnownColorShift()) {
if (isPartOfRun) {
builder.increment();
} else {
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index d2eff75..54ee0ef 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -1339,6 +1339,55 @@
EXPECT_EQ(nullptr, overrideBuffer3);
}
+TEST_F(FlattenerTest, flattenLayers_skipsLayersDisablingDimming) {
+ auto& layerState1 = mTestLayers[0]->layerState;
+ const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
+
+ auto& layerState2 = mTestLayers[1]->layerState;
+ const auto& overrideBuffer2 = layerState2->getOutputLayer()->getState().overrideInfo.buffer;
+
+ // The third layer disables dimming, which means it should not be cached
+ auto& layerState3 = mTestLayers[2]->layerState;
+ const auto& overrideBuffer3 = layerState3->getOutputLayer()->getState().overrideInfo.buffer;
+ mTestLayers[2]->layerFECompositionState.dimmingEnabled = false;
+ mTestLayers[2]->layerState->update(&mTestLayers[2]->outputLayer);
+
+ const std::vector<const LayerState*> layers = {
+ layerState1.get(),
+ layerState2.get(),
+ layerState3.get(),
+ };
+
+ initializeFlattener(layers);
+
+ mTime += 200ms;
+ initializeOverrideBuffer(layers);
+ EXPECT_EQ(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+
+ // This will render a CachedSet.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _))
+ .WillOnce(Return(ByMove(ftl::yield<FenceResult>(Fence::NO_FENCE))));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
+
+ // We've rendered a CachedSet, but we haven't merged it in.
+ EXPECT_EQ(nullptr, overrideBuffer1);
+ EXPECT_EQ(nullptr, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+
+ // This time we merge the CachedSet in, so we have a new hash, and we should
+ // only have two sets.
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, _)).Times(0);
+ initializeOverrideBuffer(layers);
+ EXPECT_NE(getNonBufferHash(layers),
+ mFlattener->flattenLayers(layers, getNonBufferHash(layers), mTime));
+ mFlattener->renderCachedSets(mOutputState, std::nullopt, true);
+
+ EXPECT_NE(nullptr, overrideBuffer1);
+ EXPECT_EQ(overrideBuffer1, overrideBuffer2);
+ EXPECT_EQ(nullptr, overrideBuffer3);
+}
+
TEST_F(FlattenerTest, flattenLayers_skipsColorLayers) {
auto& layerState1 = mTestLayers[0]->layerState;
const auto& overrideBuffer1 = layerState1->getOutputLayer()->getState().overrideInfo.buffer;
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index 044917e..39fce2b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -304,6 +304,16 @@
EXPECT_EQ(Composition::CLIENT, mLayerState->getCompositionType());
}
+TEST_F(LayerStateTest, getHdrSdrRatio) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.currentHdrSdrRatio = 2.f;
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ EXPECT_EQ(2.f, mLayerState->getHdrSdrRatio());
+}
+
TEST_F(LayerStateTest, updateCompositionType) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
@@ -1033,6 +1043,47 @@
EXPECT_TRUE(otherLayerState->compare(*mLayerState));
}
+TEST_F(LayerStateTest, updateDimmingEnabled) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.dimmingEnabled = true;
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ EXPECT_TRUE(mLayerState->isDimmingEnabled());
+
+ mock::OutputLayer newOutputLayer;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.dimmingEnabled = false;
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ ftl::Flags<LayerStateField> updates = mLayerState->update(&newOutputLayer);
+ EXPECT_EQ(ftl::Flags<LayerStateField>(LayerStateField::DimmingEnabled), updates);
+ EXPECT_FALSE(mLayerState->isDimmingEnabled());
+}
+
+TEST_F(LayerStateTest, compareDimmingEnabled) {
+ OutputLayerCompositionState outputLayerCompositionState;
+ LayerFECompositionState layerFECompositionState;
+ layerFECompositionState.dimmingEnabled = true;
+ setupMocksForLayer(mOutputLayer, *mLayerFE, outputLayerCompositionState,
+ layerFECompositionState);
+ mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+ mock::OutputLayer newOutputLayer;
+ sp<mock::LayerFE> newLayerFE = sp<mock::LayerFE>::make();
+ LayerFECompositionState layerFECompositionStateTwo;
+ layerFECompositionStateTwo.dimmingEnabled = false;
+ setupMocksForLayer(newOutputLayer, *newLayerFE, outputLayerCompositionState,
+ layerFECompositionStateTwo);
+ auto otherLayerState = std::make_unique<LayerState>(&newOutputLayer);
+
+ verifyNonUniqueDifferingFields(*mLayerState, *otherLayerState, LayerStateField::DimmingEnabled);
+
+ EXPECT_TRUE(mLayerState->compare(*otherLayerState));
+ EXPECT_TRUE(otherLayerState->compare(*mLayerState));
+}
+
TEST_F(LayerStateTest, dumpDoesNotCrash) {
OutputLayerCompositionState outputLayerCompositionState;
LayerFECompositionState layerFECompositionState;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 867f3af..028bd19 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -585,11 +585,13 @@
return false;
}
- static constexpr uint64_t deniedFlags = layer_state_t::eProducerDisconnect |
- layer_state_t::eLayerChanged | layer_state_t::eRelativeLayerChanged |
- layer_state_t::eTransparentRegionChanged | layer_state_t::eFlagsChanged |
- layer_state_t::eBlurRegionsChanged | layer_state_t::eLayerStackChanged |
- layer_state_t::eAutoRefreshChanged | layer_state_t::eReparent;
+ const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
+ layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
+ layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
+ layer_state_t::eLayerStackChanged | layer_state_t::eReparent |
+ (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
+ ? 0
+ : layer_state_t::eAutoRefreshChanged);
if (s.what & deniedFlags) {
ATRACE_FORMAT_INSTANT("%s: false [has denied flags 0x%" PRIx64 "]", __func__,
s.what & deniedFlags);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 80eee15..073bad3 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3792,8 +3792,10 @@
const uint64_t deniedFlags = layer_state_t::eProducerDisconnect | layer_state_t::eLayerChanged |
layer_state_t::eRelativeLayerChanged | layer_state_t::eTransparentRegionChanged |
layer_state_t::eFlagsChanged | layer_state_t::eBlurRegionsChanged |
- layer_state_t::eLayerStackChanged | layer_state_t::eAutoRefreshChanged |
- layer_state_t::eReparent;
+ layer_state_t::eLayerStackChanged | layer_state_t::eReparent |
+ (FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
+ ? 0
+ : layer_state_t::eAutoRefreshChanged);
if ((s.what & requiredFlags) != requiredFlags) {
ATRACE_FORMAT_INSTANT("%s: false [missing required flags 0x%" PRIx64 "]", __func__,
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index d9334d6..12043d4 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -140,6 +140,8 @@
DUMP_READ_ONLY_FLAG(ce_fence_promise);
DUMP_READ_ONLY_FLAG(idle_screen_refresh_rate_timeout);
DUMP_READ_ONLY_FLAG(graphite_renderengine);
+ DUMP_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed);
+
#undef DUMP_READ_ONLY_FLAG
#undef DUMP_SERVER_FLAG
#undef DUMP_FLAG_INTERVAL
@@ -229,6 +231,7 @@
FLAG_MANAGER_READ_ONLY_FLAG(protected_if_client, "")
FLAG_MANAGER_READ_ONLY_FLAG(ce_fence_promise, "");
FLAG_MANAGER_READ_ONLY_FLAG(graphite_renderengine, "debug.renderengine.graphite")
+FLAG_MANAGER_READ_ONLY_FLAG(latch_unsignaled_with_auto_refresh_changed, "");
/// Trunk stable server flags ///
FLAG_MANAGER_SERVER_FLAG(refresh_rate_overlay_on_external_display, "")
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 819e587..0239eb0 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -78,6 +78,7 @@
bool ce_fence_promise() const;
bool idle_screen_refresh_rate_timeout() const;
bool graphite_renderengine() const;
+ bool latch_unsignaled_with_auto_refresh_changed() const;
protected:
// overridden for unit tests
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index a8fd6b7..d7b220f 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -39,4 +39,15 @@
}
} # frame_rate_category_mrr
+flag {
+ name: "latch_unsignaled_with_auto_refresh_changed"
+ namespace: "core_graphics"
+ description: "Ignore eAutoRefreshChanged with latch unsignaled"
+ bug: "331513837"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+} # latch_unsignaled_with_auto_refresh_changed
+
# IMPORTANT - please keep alphabetize to reduce merge conflicts
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 1f2a1ed..7fb9247 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "TransactionApplicationTest"
+#include <common/test/FlagUtils.h>
#include <compositionengine/Display.h>
#include <compositionengine/mock/DisplaySurface.h>
#include <gmock/gmock.h>
@@ -34,8 +35,11 @@
#include "TestableSurfaceFlinger.h"
#include "TransactionState.h"
+#include <com_android_graphics_surfaceflinger_flags.h>
+
namespace android {
+using namespace com::android::graphics::surfaceflinger;
using testing::_;
using testing::Return;
@@ -498,6 +502,44 @@
setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
}
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_AutoRefreshChanged) {
+ SET_FLAG_FOR_TEST(flags::latch_unsignaled_with_auto_refresh_changed, false);
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsPending = 1u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eAutoRefreshChanged |
+ layer_state_t::
+ eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
+}
+
+TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesUnSignaledInTheQueue_AutoRefreshChanged) {
+ SET_FLAG_FOR_TEST(flags::latch_unsignaled_with_auto_refresh_changed, true);
+ const sp<IBinder> kApplyToken =
+ IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ const auto kLayerId = 1;
+ const auto kExpectedTransactionsPending = 0u;
+
+ const auto unsignaledTransaction =
+ createTransactionInfo(kApplyToken,
+ {
+ createComposerState(kLayerId,
+ fence(Fence::Status::Unsignaled),
+ layer_state_t::eAutoRefreshChanged |
+ layer_state_t::
+ eBufferChanged),
+ });
+ setTransactionStates({unsignaledTransaction}, kExpectedTransactionsPending);
+}
+
TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed) {
const sp<IBinder> kApplyToken =
IInterface::asBinder(TransactionCompletedListener::getIInstance());