VTS for the Refresh rate callback debug enabled
BUG: 202734676
Test: atest VtsHalGraphicsComposer3_TargetTest
with the patch of
Ibc80d66eae6b21c3cf84d35fa819e97ccc509ede
Change-Id: I02bdf061420fe12ef4548008d66bb73e8cd416e8
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
index 4fb5d01..7b3a2b4 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp
@@ -29,6 +29,11 @@
mVsyncAllowed = allowed;
}
+void GraphicsComposerCallback::setRefreshRateChangedDebugDataEnabledCallbackAllowed(bool allowed) {
+ std::scoped_lock lock(mMutex);
+ mRefreshRateChangedDebugDataEnabledCallbackAllowed = allowed;
+}
+
std::vector<int64_t> GraphicsComposerCallback::getDisplays() const {
std::scoped_lock lock(mMutex);
return mDisplays;
@@ -79,6 +84,21 @@
return ret;
}
+std::vector<RefreshRateChangedDebugData>
+GraphicsComposerCallback::takeListOfRefreshRateChangedDebugData() {
+ std::scoped_lock lock(mMutex);
+
+ std::vector<RefreshRateChangedDebugData> ret;
+ ret.swap(mRefreshRateChangedDebugData);
+
+ return ret;
+}
+
+int32_t GraphicsComposerCallback::getInvalidRefreshRateDebugEnabledCallbackCount() const {
+ std::scoped_lock lock(mMutex);
+ return mInvalidRefreshRateDebugEnabledCallbackCount;
+}
+
::ndk::ScopedAStatus GraphicsComposerCallback::onHotplug(int64_t in_display, bool in_connected) {
std::scoped_lock lock(mMutex);
@@ -125,9 +145,16 @@
}
::ndk::ScopedAStatus GraphicsComposerCallback::onRefreshRateChangedDebug(
- const RefreshRateChangedDebugData&) {
- // TODO(b/202734676) Add implementation for Vts tests
- return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ const RefreshRateChangedDebugData& data) {
+ std::scoped_lock lock(mMutex);
+
+ const auto it = std::find(mDisplays.begin(), mDisplays.end(), data.display);
+ if (mRefreshRateChangedDebugDataEnabledCallbackAllowed && it != mDisplays.end()) {
+ mRefreshRateChangedDebugData.push_back(data);
+ } else {
+ mInvalidRefreshRateDebugEnabledCallbackCount++;
+ }
+ return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus GraphicsComposerCallback::onVsyncPeriodTimingChanged(
diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
index 9c3bc70..13e992a 100644
--- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h
@@ -26,6 +26,8 @@
public:
void setVsyncAllowed(bool allowed);
+ void setRefreshRateChangedDebugDataEnabledCallbackAllowed(bool allowed);
+
std::vector<int64_t> getDisplays() const;
int32_t getInvalidHotplugCount() const;
@@ -44,6 +46,10 @@
std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
+ std::vector<RefreshRateChangedDebugData> takeListOfRefreshRateChangedDebugData();
+
+ int32_t getInvalidRefreshRateDebugEnabledCallbackCount() const;
+
private:
virtual ::ndk::ScopedAStatus onHotplug(int64_t in_display, bool in_connected) override;
virtual ::ndk::ScopedAStatus onRefresh(int64_t in_display) override;
@@ -63,9 +69,13 @@
std::vector<int64_t> mDisplays GUARDED_BY(mMutex);
// true only when vsync is enabled
bool mVsyncAllowed GUARDED_BY(mMutex) = true;
+ // true only when RefreshRateChangedCallbackDebugEnabled is set to true.
+ bool mRefreshRateChangedDebugDataEnabledCallbackAllowed GUARDED_BY(mMutex) = false;
std::optional<VsyncPeriodChangeTimeline> mTimeline GUARDED_BY(mMutex);
+ std::vector<RefreshRateChangedDebugData> mRefreshRateChangedDebugData GUARDED_BY(mMutex);
+
int32_t mVsyncIdleCount GUARDED_BY(mMutex) = 0;
int64_t mVsyncIdleTime GUARDED_BY(mMutex) = 0;
@@ -75,6 +85,7 @@
int32_t mInvalidVsyncCount GUARDED_BY(mMutex) = 0;
int32_t mInvalidVsyncPeriodChangeCount GUARDED_BY(mMutex) = 0;
int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0;
+ int32_t mInvalidRefreshRateDebugEnabledCallbackCount GUARDED_BY(mMutex) = 0;
};
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index e03ef25..25b0ca0 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -119,6 +119,24 @@
return updateDisplayProperties(vtsDisplay, config);
}
+ScopedAStatus VtsComposerClient::setPeakRefreshRateConfig(VtsDisplay* vtsDisplay) {
+ const auto displayId = vtsDisplay->getDisplayId();
+ auto [activeStatus, activeConfig] = getActiveConfig(displayId);
+ EXPECT_TRUE(activeStatus.isOk());
+ auto peakDisplayConfig = vtsDisplay->getDisplayConfig(activeConfig);
+ auto peakConfig = activeConfig;
+
+ const auto displayConfigs = vtsDisplay->getDisplayConfigs();
+ for (const auto [config, displayConfig] : displayConfigs) {
+ if (displayConfig.configGroup == peakDisplayConfig.configGroup &&
+ displayConfig.vsyncPeriod < peakDisplayConfig.vsyncPeriod) {
+ peakDisplayConfig = displayConfig;
+ peakConfig = config;
+ }
+ }
+ return setActiveConfig(vtsDisplay, peakConfig);
+}
+
std::pair<ScopedAStatus, int32_t> VtsComposerClient::getDisplayAttribute(
int64_t display, int32_t config, DisplayAttribute displayAttribute) {
int32_t outDisplayAttribute;
@@ -375,10 +393,15 @@
return mComposerCallback->getVsyncIdleTime();
}
-ndk::ScopedAStatus VtsComposerClient::setRefreshRateChangedCallbackDebugEnabled(
- int64_t /* display */, bool /* enabled */) {
- // TODO(b/202734676) Add implementation for VTS tests
- return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ndk::ScopedAStatus VtsComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t display,
+ bool enabled) {
+ mComposerCallback->setRefreshRateChangedDebugDataEnabledCallbackAllowed(enabled);
+ return mComposerClient->setRefreshRateChangedCallbackDebugEnabled(display, enabled);
+}
+
+std::vector<RefreshRateChangedDebugData>
+VtsComposerClient::takeListOfRefreshRateChangedDebugData() {
+ return mComposerCallback->takeListOfRefreshRateChangedDebugData();
}
int64_t VtsComposerClient::getInvalidDisplayId() {
@@ -545,6 +568,10 @@
ALOGE("Invalid seamless possible count");
isValid = false;
}
+ if (mComposerCallback->getInvalidRefreshRateDebugEnabledCallbackCount() != 0) {
+ ALOGE("Invalid refresh rate debug enabled callback count");
+ isValid = false;
+ }
}
return isValid;
}
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index 81a62b3..ea3318c 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -77,6 +77,8 @@
ScopedAStatus setActiveConfig(VtsDisplay* vtsDisplay, int32_t config);
+ ScopedAStatus setPeakRefreshRateConfig(VtsDisplay* vtsDisplay);
+
std::pair<ScopedAStatus, int32_t> getDisplayAttribute(int64_t display, int32_t config,
DisplayAttribute displayAttribute);
@@ -183,6 +185,10 @@
std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
+ ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled);
+
+ std::vector<RefreshRateChangedDebugData> takeListOfRefreshRateChangedDebugData();
+
private:
ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
@@ -197,9 +203,6 @@
bool verifyComposerCallbackParams();
- ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */,
- bool /* enabled */);
-
// Keep track of displays and layers. When a test fails/ends,
// the VtsComposerClient::tearDown should be called from the
// test tearDown to clean up the resources for the test.
@@ -245,15 +248,17 @@
};
void addDisplayConfig(int32_t config, DisplayConfig displayConfig) {
- displayConfigs.insert({config, displayConfig});
+ mDisplayConfigs.insert({config, displayConfig});
}
- DisplayConfig getDisplayConfig(int32_t config) { return displayConfigs.find(config)->second; }
+ DisplayConfig getDisplayConfig(int32_t config) { return mDisplayConfigs.find(config)->second; }
+
+ std::unordered_map<int32_t, DisplayConfig> getDisplayConfigs() { return mDisplayConfigs; }
private:
int64_t mDisplayId;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
- std::unordered_map<int32_t, DisplayConfig> displayConfigs;
+ std::unordered_map<int32_t, DisplayConfig> mDisplayConfigs;
};
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index 4974e71..37576b9 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1217,6 +1217,14 @@
}
}
+ bool checkIfCallbackRefreshRateChangedDebugEnabledReceived(
+ std::function<bool(RefreshRateChangedDebugData)> filter) {
+ const auto list = mComposerClient->takeListOfRefreshRateChangedDebugData();
+ return std::any_of(list.begin(), list.end(), [&](auto refreshRateChangedDebugData) {
+ return filter(refreshRateChangedDebugData);
+ });
+ }
+
sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
return sp<GraphicBuffer>::make(
static_cast<uint32_t>(getPrimaryDisplay().getDisplayWidth()),
@@ -1316,7 +1324,7 @@
return vsyncPeriod;
}
- int64_t createOnScreenLayer() {
+ int64_t createOnScreenLayer(Composition composition = Composition::DEVICE) {
const auto& [status, layer] =
mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount);
EXPECT_TRUE(status.isOk());
@@ -1324,12 +1332,25 @@
getPrimaryDisplay().getDisplayHeight()};
FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(),
(float)getPrimaryDisplay().getDisplayHeight()};
- configureLayer(getPrimaryDisplay(), layer, Composition::DEVICE, displayFrame, cropRect);
+ configureLayer(getPrimaryDisplay(), layer, composition, displayFrame, cropRect);
auto& writer = getWriter(getPrimaryDisplayId());
writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN);
return layer;
}
+ void sendBufferUpdate(int64_t layer) {
+ const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888);
+ ASSERT_NE(nullptr, buffer->handle);
+
+ auto& writer = getWriter(getPrimaryDisplayId());
+ writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle,
+ /*acquireFence*/ -1);
+
+ const sp<::android::Fence> presentFence =
+ presentAndGetFence(ComposerClientWriter::kNoTimestamp);
+ presentFence->waitForever(LOG_TAG);
+ }
+
bool hasDisplayCapability(int64_t display, DisplayCapability cap) {
const auto& [status, capabilities] = mComposerClient->getDisplayCapabilities(display);
EXPECT_TRUE(status.isOk());
@@ -2268,6 +2289,179 @@
EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk());
}
+TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Unsupported) {
+ if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
+ auto status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(
+ getPrimaryDisplayId(), /*enabled*/ true);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_NO_FATAL_FAILURE(
+ assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
+
+ status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(getPrimaryDisplayId(),
+ /*enabled*/ false);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_NO_FATAL_FAILURE(
+ assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
+ }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Enabled) {
+ if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
+ GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
+ return;
+ }
+
+ const auto displayId = getPrimaryDisplayId();
+ EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+ // Enable the callback
+ ASSERT_TRUE(mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+ /*enabled*/ true)
+ .isOk());
+ std::this_thread::sleep_for(100ms);
+
+ const bool isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived(
+ [&](auto refreshRateChangedDebugData) {
+ return displayId == refreshRateChangedDebugData.display;
+ });
+
+ // Check that we immediately got a callback
+ EXPECT_TRUE(isCallbackReceived);
+
+ ASSERT_TRUE(mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+ /*enabled*/ false)
+ .isOk());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest,
+ SetRefreshRateChangedCallbackDebugEnabled_noCallbackWhenIdle) {
+ if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
+ GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
+ return;
+ }
+
+ auto display = getEditablePrimaryDisplay();
+ const auto displayId = display.getDisplayId();
+
+ if (!hasDisplayCapability(displayId, DisplayCapability::DISPLAY_IDLE_TIMER)) {
+ GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+ return;
+ }
+
+ EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+ EXPECT_TRUE(mComposerClient->setPeakRefreshRateConfig(&display).isOk());
+
+ ASSERT_TRUE(mComposerClient->setIdleTimerEnabled(displayId, /*timeoutMs*/ 500).isOk());
+ // Enable the callback
+ ASSERT_TRUE(mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+ /*enabled*/ true)
+ .isOk());
+
+ const bool isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived(
+ [&](auto refreshRateChangedDebugData) {
+ return displayId == refreshRateChangedDebugData.display;
+ });
+
+ int retryCount = 3;
+ do {
+ // Wait for 1s so that we enter the idle state
+ std::this_thread::sleep_for(1s);
+ if (!isCallbackReceived) {
+ // DID NOT receive a callback, we are in the idle state.
+ break;
+ }
+ } while (--retryCount > 0);
+
+ if (retryCount == 0) {
+ GTEST_SUCCEED() << "Unable to enter the idle mode";
+ return;
+ }
+
+ // Send the REFRESH_RATE_INDICATOR update
+ ASSERT_NO_FATAL_FAILURE(
+ sendBufferUpdate(createOnScreenLayer(Composition::REFRESH_RATE_INDICATOR)));
+ std::this_thread::sleep_for(1s);
+ EXPECT_FALSE(isCallbackReceived)
+ << "A callback should not be received for REFRESH_RATE_INDICATOR";
+
+ EXPECT_TRUE(mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId,
+ /*enabled*/ false)
+ .isOk());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest,
+ SetRefreshRateChangedCallbackDebugEnabled_SetActiveConfigWithConstraints) {
+ if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) {
+ GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported";
+ return;
+ }
+
+ VsyncPeriodChangeConstraints constraints;
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ for (VtsDisplay& display : mDisplays) {
+ const auto displayId = display.getDisplayId();
+ EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk());
+
+ // Enable the callback
+ ASSERT_TRUE(mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ true)
+ .isOk());
+
+ forEachTwoConfigs(displayId, [&](int32_t config1, int32_t config2) {
+ const int32_t vsyncPeriod1 = display.getDisplayConfig(config1).vsyncPeriod;
+ const int32_t vsyncPeriod2 = display.getDisplayConfig(config2).vsyncPeriod;
+
+ if (vsyncPeriod1 == vsyncPeriod2) {
+ return; // continue
+ }
+
+ EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config1).isOk());
+ sendRefreshFrame(display, nullptr);
+
+ const auto& [status, timeline] =
+ mComposerClient->setActiveConfigWithConstraints(&display, config2, constraints);
+ EXPECT_TRUE(status.isOk());
+
+ if (timeline.refreshRequired) {
+ sendRefreshFrame(display, &timeline);
+ }
+
+ const auto isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived(
+ [&](auto refreshRateChangedDebugData) {
+ constexpr int kVsyncThreshold = 1000;
+ return displayId == refreshRateChangedDebugData.display &&
+ std::abs(vsyncPeriod2 -
+ refreshRateChangedDebugData.vsyncPeriodNanos) <=
+ kVsyncThreshold;
+ });
+
+ int retryCount = 3;
+ do {
+ std::this_thread::sleep_for(100ms);
+ if (isCallbackReceived) {
+ GTEST_SUCCEED() << "Received a callback successfully";
+ break;
+ }
+ } while (--retryCount > 0);
+
+ if (retryCount == 0) {
+ GTEST_FAIL() << "failed to get a callback for the display " << displayId
+ << " with config " << config2;
+ }
+ });
+
+ EXPECT_TRUE(
+ mComposerClient
+ ->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ false)
+ .isOk());
+ }
+}
+
/*
* Test that no two display configs are exactly the same.
*/