composer: add API to control display idle timer
Add new functions to control display idle timer
- Adding an API to r configure display idle timer.
- Extend DisplayCapability to query display support idle timer.
- Adding an callback for notify client the display is idle, the refresh
rate changed to a lower setting to preserve power and vsync cadence
changed. The client can enable vsync callback to learn the new vsync
cadence before sending a new frame.
Bug: 194068871
Bug: 198808492
Test: build, vts
Change-Id: I47649d222022922926a05f2d700ca798f8f48b35
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
index fdf1100..b41ac8a 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -42,4 +42,5 @@
AUTO_LOW_LATENCY_MODE = 5,
SUSPEND = 6,
DISPLAY_DECORATION = 7,
+ DISPLAY_IDLE_TIMER = 8,
}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
index f82d02e..21620e7 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -39,4 +39,5 @@
oneway void onSeamlessPossible(long display);
oneway void onVsync(long display, long timestamp, int vsyncPeriodNanos);
oneway void onVsyncPeriodTimingChanged(long display, in android.hardware.graphics.composer3.VsyncPeriodChangeTimeline updatedTimeline);
+ oneway void onVsyncIdle(long display);
}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index 5593c57..2de699b 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -73,6 +73,7 @@
void setPowerMode(long display, android.hardware.graphics.composer3.PowerMode mode);
void setReadbackBuffer(long display, in android.hardware.common.NativeHandle buffer, in @nullable ParcelFileDescriptor releaseFence);
void setVsyncEnabled(long display, boolean enabled);
+ void setIdleTimerEnabled(long display, int timeoutMs);
const int EX_BAD_CONFIG = 1;
const int EX_BAD_DISPLAY = 2;
const int EX_BAD_LAYER = 3;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
index 249fed0..85136c4 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCapability.aidl
@@ -79,4 +79,9 @@
* Indicates that the display supports Composition.DISPLAY_DECORATION.
*/
DISPLAY_DECORATION = 7,
+ /**
+ * Indicates that the display supports IComposerClient.setIdleTimerEnabled and
+ * IComposerCallback.onVsyncIdle.
+ */
+ DISPLAY_IDLE_TIMER = 8,
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
index ac95b41..67954d4 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerCallback.aidl
@@ -86,4 +86,14 @@
*/
oneway void onVsyncPeriodTimingChanged(
long display, in VsyncPeriodChangeTimeline updatedTimeline);
+
+ /**
+ * Notifies the client that the display is idle, the refresh rate changed to a lower setting to
+ * preserve power and vsync cadence changed. When a new frame is queued for presentation, the
+ * client is expected to enable vsync callbacks to learn the new vsync cadence before sending
+ * a new frame.
+ *
+ * @param display is the display whose vsync cadence changed due to panel idle mode.
+ */
+ oneway void onVsyncIdle(long display);
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index c86b9bd..2fe6656 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -779,4 +779,25 @@
* @exception EX_BAD_PARAMETER when enabled was an invalid value.
*/
void setVsyncEnabled(long display, boolean enabled);
+
+ /**
+ * Enables or disables the idle timer on this display.
+ *
+ * Idle timer is used to allow the display to go into a panel idle mode after some
+ * idle period.
+ *
+ * This function should only be called if the display reports support for
+ * DisplayCapability.DISPLAY_IDLE from getDisplayCapabilities.
+ *
+ * @param display is the display to which the idle timer is set.
+ * @param timeoutMs is the minimum requirements of idle period in milliseconds. Panel
+ * should not go into the idle state within the minimum requirement after
+ * idle for a while. 0 means disabled, panel should not go into idle state.
+ *
+ * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+ * @exception EX_BAD_PARAMETER when timeout is a negative number.
+ * @exception EX_UNSUPPORTED when idle is not supported on this display.
+ *
+ */
+ void setIdleTimerEnabled(long display, int timeoutMs);
}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
index 1cfd3f9..1c84674 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1383,6 +1383,14 @@
return layer;
}
+ bool hasDisplayCapability(int64_t display, DisplayCapability cap) {
+ std::vector<DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(display, &capabilities);
+ EXPECT_TRUE(error.isOk());
+
+ return std::find(capabilities.begin(), capabilities.end(), cap) != capabilities.end();
+ }
+
void Test_setActiveConfigWithConstraints(const TestParameters& params) {
for (VtsDisplay& display : mDisplays) {
forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
@@ -2134,6 +2142,74 @@
ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(5));
}
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Unsupported) {
+ const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+ DisplayCapability::DISPLAY_IDLE_TIMER);
+ if (!hasDisplayIdleTimerSupport) {
+ const auto error = mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0);
+ EXPECT_FALSE(error.isOk());
+ EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
+ }
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_BadParameter) {
+ const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+ DisplayCapability::DISPLAY_IDLE_TIMER);
+ if (!hasDisplayIdleTimerSupport) {
+ GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+ return;
+ }
+
+ const auto error = mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, -1);
+ EXPECT_FALSE(error.isOk());
+ EXPECT_EQ(IComposerClient::EX_BAD_PARAMETER, error.getServiceSpecificError());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Disable) {
+ const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+ DisplayCapability::DISPLAY_IDLE_TIMER);
+ if (!hasDisplayIdleTimerSupport) {
+ GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+ return;
+ }
+
+ EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0).isOk());
+ std::this_thread::sleep_for(1s);
+ EXPECT_EQ(0, mComposerCallback->getVsyncIdleCount());
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, setIdleTimerEnabled_Timeout_2) {
+ const bool hasDisplayIdleTimerSupport = hasDisplayCapability(mPrimaryDisplay,
+ DisplayCapability::DISPLAY_IDLE_TIMER);
+ if (!hasDisplayIdleTimerSupport) {
+ GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported";
+ return;
+ }
+
+ EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+ EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 0).isOk());
+
+ const auto buffer = allocate();
+ ASSERT_NE(nullptr, buffer->handle);
+
+ const auto layer = createOnScreenLayer();
+ mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer->handle, -1);
+ int32_t vsyncIdleCount = mComposerCallback->getVsyncIdleCount();
+ auto earlyVsyncIdleTime = systemTime() + std::chrono::nanoseconds(2s).count();
+ EXPECT_TRUE(mComposerClient->setIdleTimerEnabled(mPrimaryDisplay, 2000).isOk());
+
+ const sp<::android::Fence> presentFence =
+ presentAndGetFence(ComposerClientWriter::kNoTimestamp);
+ presentFence->waitForever(LOG_TAG);
+
+ std::this_thread::sleep_for(3s);
+ if (vsyncIdleCount < mComposerCallback->getVsyncIdleCount()) {
+ EXPECT_GE(mComposerCallback->getVsyncIdleTime(), earlyVsyncIdleTime);
+ }
+
+ EXPECT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerAidlCommandTest,
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
index 307fe15..22b5d79 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/GraphicsComposerCallback.cpp
@@ -16,6 +16,7 @@
#include "include/GraphicsComposerCallback.h"
#include <log/log_main.h>
+#include <utils/Timers.h>
#pragma push_macro("LOG_TAG")
#undef LOG_TAG
@@ -58,6 +59,16 @@
return mInvalidSeamlessPossibleCount;
}
+int32_t GraphicsComposerCallback::getVsyncIdleCount() const {
+ std::scoped_lock lock(mMutex);
+ return mVsyncIdleCount;
+}
+
+int64_t GraphicsComposerCallback::getVsyncIdleTime() const {
+ std::scoped_lock lock(mMutex);
+ return mVsyncIdleTime;
+}
+
std::optional<VsyncPeriodChangeTimeline>
GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() {
std::scoped_lock lock(mMutex);
@@ -125,4 +136,13 @@
return ::ndk::ScopedAStatus::ok();
}
+::ndk::ScopedAStatus GraphicsComposerCallback::onVsyncIdle(int64_t in_display) {
+ std::scoped_lock lock(mMutex);
+ if (mDisplays.count(in_display)) {
+ mVsyncIdleCount++;
+ mVsyncIdleTime = systemTime();
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
index c359d5e..f25f36d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/GraphicsComposerCallback.h
@@ -45,6 +45,10 @@
int32_t getInvalidSeamlessPossibleCount() const;
+ int32_t getVsyncIdleCount() const;
+
+ int64_t getVsyncIdleTime() const;
+
std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
private:
@@ -57,6 +61,7 @@
int64_t in_display,
const ::aidl::android::hardware::graphics::composer3::VsyncPeriodChangeTimeline&
in_updatedTimeline) override;
+ virtual ::ndk::ScopedAStatus onVsyncIdle(int64_t in_display) override;
mutable std::mutex mMutex;
// the set of all currently connected displays
@@ -66,6 +71,9 @@
std::optional<VsyncPeriodChangeTimeline> mTimeline GUARDED_BY(mMutex);
+ int32_t mVsyncIdleCount GUARDED_BY(mMutex) = 0;
+ int64_t mVsyncIdleTime GUARDED_BY(mMutex) = 0;
+
// track invalid callbacks
int32_t mInvalidHotplugCount GUARDED_BY(mMutex) = 0;
int32_t mInvalidRefreshCount GUARDED_BY(mMutex) = 0;
@@ -74,4 +82,4 @@
int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0;
};
-} // namespace aidl::android::hardware::graphics::composer3::vts
\ No newline at end of file
+} // namespace aidl::android::hardware::graphics::composer3::vts