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