composer: pass expetcedPresentTime

Add expectedPresentTime as an optional field to DisplayCommand.

Test: VTS
Bug: 198186194
Change-Id: I1203422b5d052508ca42a80da5d252c106efc5ee
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
new file mode 100644
index 0000000..856ec64
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable ClockMonotonicTimestamp {
+  long timestamp;
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
index 2f5d00f..35a1eed 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -39,6 +39,7 @@
   @nullable android.hardware.graphics.composer3.ColorTransformPayload colorTransform;
   @nullable android.hardware.graphics.composer3.ClientTarget clientTarget;
   @nullable android.hardware.graphics.composer3.Buffer virtualDisplayOutputBuffer;
+  @nullable android.hardware.graphics.composer3.ClockMonotonicTimestamp expectedPresentTime;
   boolean validateDisplay;
   boolean acceptDisplayChanges;
   boolean presentDisplay;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
new file mode 100644
index 0000000..f385038
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/ClockMonotonicTimestamp.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+/**
+ * Represents a nanoseconds timestamp in CLOCK_MONOTONIC.
+ */
+@VintfStability
+parcelable ClockMonotonicTimestamp {
+    long timestamp;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
index 21497c4..fdaf35a 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayCommand.aidl
@@ -18,6 +18,7 @@
 
 import android.hardware.graphics.composer3.Buffer;
 import android.hardware.graphics.composer3.ClientTarget;
+import android.hardware.graphics.composer3.ClockMonotonicTimestamp;
 import android.hardware.graphics.composer3.ColorTransformPayload;
 import android.hardware.graphics.composer3.LayerCommand;
 
@@ -115,6 +116,14 @@
     @nullable Buffer virtualDisplayOutputBuffer;
 
     /**
+     * Sets the expected present time to present the current content on screen.
+     * The implementation should try to present the display as close as possible
+     * to the given expectedPresentTime. If expectedPresentTime is 0, the
+     * implementation should present the display as soon as possible.
+     */
+    @nullable ClockMonotonicTimestamp expectedPresentTime;
+
+    /**
      * Instructs the device to inspect all of the layer state and determine if
      * there are any composition type changes necessary before presenting the
      * display. Permitted changes are described in the definition of
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 34dea9e..eddc2d3 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -258,7 +258,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         // if hwc cannot handle and asks for composition change,
         // just succeed the test
@@ -317,7 +317,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
 
         std::vector<int64_t> changedCompositionLayers;
@@ -377,7 +377,7 @@
                                       mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace);
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
 
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
 
         std::vector<int64_t> changedCompositionLayers;
@@ -492,7 +492,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
 
         std::vector<int64_t> changedCompositionLayers;
@@ -606,7 +606,7 @@
         clientLayer->setDisplayFrame(clientFrame);
         clientLayer->setZOrder(0);
         clientLayer->write(mWriter);
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
 
         std::vector<int64_t> changedCompositionLayers;
@@ -685,7 +685,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -715,7 +715,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         ASSERT_TRUE(mReader.takeErrors().empty());
         mReader.takeChangedCompositionTypes(mPrimaryDisplay, &changedCompositionLayers,
@@ -756,7 +756,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -819,7 +819,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -877,7 +877,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -902,7 +902,7 @@
 
         writeLayers(layers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         mReader.takeChangedCompositionTypes(mPrimaryDisplay, &changedCompositionLayers,
                                             &changedCompositionTypes);
@@ -1027,7 +1027,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -1072,7 +1072,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -1112,7 +1112,7 @@
         ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -1195,7 +1195,7 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -1241,7 +1241,7 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> changedCompositionLayers;
         std::vector<Composition> changedCompositionTypes;
@@ -1287,7 +1287,7 @@
 
         writeLayers(mLayers);
         ASSERT_TRUE(mReader.takeErrors().empty());
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> layers;
         std::vector<Composition> types;
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 1f30475..19b1fb2 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
@@ -17,6 +17,7 @@
 #include <android/hardware/graphics/composer3/ComposerClientWriter.h>
 #include <binder/ProcessState.h>
 #include <gtest/gtest.h>
+#include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <algorithm>
@@ -993,14 +994,14 @@
 
 TEST_P(GraphicsComposerAidlTest, SetPowerModeUnsupported) {
     std::vector<DisplayCapability> capabilities;
-    const auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
+    auto error = mComposerClient->getDisplayCapabilities(mPrimaryDisplay, &capabilities);
     ASSERT_TRUE(error.isOk());
     const bool isDozeSupported = std::find(capabilities.begin(), capabilities.end(),
                                            DisplayCapability::DOZE) != capabilities.end();
     const bool isSuspendSupported = std::find(capabilities.begin(), capabilities.end(),
                                               DisplayCapability::SUSPEND) != capabilities.end();
     if (!isDozeSupported) {
-        auto error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE);
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::DOZE);
         EXPECT_FALSE(error.isOk());
         EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
 
@@ -1010,7 +1011,7 @@
     }
 
     if (!isSuspendSupported) {
-        auto error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON_SUSPEND);
+        error = mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON_SUSPEND);
         EXPECT_FALSE(error.isOk());
         EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, error.getServiceSpecificError());
 
@@ -1283,7 +1284,7 @@
             mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1);
             mWriter.setLayerDataspace(display.get(), layer, common::Dataspace::UNKNOWN);
 
-            mWriter.validateDisplay(display.get());
+            mWriter.validateDisplay(display.get(), ComposerClientWriter::kNoTimestamp);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1299,7 +1300,7 @@
             mWriter.setLayerBuffer(display.get(), layer, 0, buffer->handle, -1);
             mWriter.setLayerSurfaceDamage(display.get(), layer,
                                           std::vector<Rect>(1, {0, 0, 10, 10}));
-            mWriter.validateDisplay(display.get());
+            mWriter.validateDisplay(display.get(), ComposerClientWriter::kNoTimestamp);
             execute();
             ASSERT_TRUE(mReader.takeErrors().empty());
 
@@ -1310,6 +1311,53 @@
         ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
     }
 
+    sp<::android::Fence> presentAndGetFence(
+            std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        mWriter.validateDisplay(mPrimaryDisplay, expectedPresentTime);
+        execute();
+        EXPECT_TRUE(mReader.takeErrors().empty());
+
+        mWriter.presentDisplay(mPrimaryDisplay);
+        execute();
+        EXPECT_TRUE(mReader.takeErrors().empty());
+
+        int presentFence;
+        mReader.takePresentFence(mPrimaryDisplay, &presentFence);
+        EXPECT_NE(-1, presentFence);
+        return sp<::android::Fence>::make(presentFence);
+    }
+
+    int32_t getVsyncPeriod() {
+        int32_t activeConfig;
+        EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk());
+
+        int32_t vsyncPeriod;
+        EXPECT_TRUE(mComposerClient
+                            ->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                  DisplayAttribute::VSYNC_PERIOD, &vsyncPeriod)
+                            .isOk());
+        return vsyncPeriod;
+    }
+
+    int64_t createOnScreenLayer() {
+        const int64_t layer = createLayer(mDisplays[0]);
+        mWriter.setLayerCompositionType(mPrimaryDisplay, layer, Composition::DEVICE);
+        mWriter.setLayerDisplayFrame(mPrimaryDisplay, layer, {0, 0, mDisplayWidth, mDisplayHeight});
+        mWriter.setLayerPlaneAlpha(mPrimaryDisplay, layer, 1);
+        mWriter.setLayerSourceCrop(
+                mPrimaryDisplay, layer,
+                {0, 0, static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
+        mWriter.setLayerTransform(mPrimaryDisplay, layer, static_cast<Transform>(0));
+        mWriter.setLayerVisibleRegion(mPrimaryDisplay, layer,
+                                      std::vector<Rect>(1, {0, 0, mDisplayWidth, mDisplayHeight}));
+        mWriter.setLayerZOrder(mPrimaryDisplay, layer, 10);
+        mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
+        mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer,
+                                      std::vector<Rect>(1, {0, 0, mDisplayWidth, mDisplayHeight}));
+        mWriter.setLayerDataspace(mPrimaryDisplay, layer, common::Dataspace::UNKNOWN);
+        return layer;
+    }
+
     void Test_setActiveConfigWithConstraints(const TestParameters& params) {
         for (VtsDisplay& display : mDisplays) {
             forEachTwoConfigs(display.get(), [&](int32_t config1, int32_t config2) {
@@ -1400,6 +1448,47 @@
         }
     }
 
+    void Test_expectedPresentTime(std::optional<int> framesDelay) {
+        ASSERT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON).isOk());
+
+        const auto vsyncPeriod = getVsyncPeriod();
+
+        const auto buffer1 = allocate();
+        const auto buffer2 = allocate();
+        ASSERT_NE(nullptr, buffer1);
+        ASSERT_NE(nullptr, buffer2);
+
+        const auto layer = createOnScreenLayer();
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer1->handle, -1);
+        const sp<::android::Fence> presentFence1 =
+                presentAndGetFence(ComposerClientWriter::kNoTimestamp);
+        presentFence1->waitForever(LOG_TAG);
+
+        auto expectedPresentTime = presentFence1->getSignalTime() + vsyncPeriod;
+        if (framesDelay.has_value()) {
+            expectedPresentTime += *framesDelay * vsyncPeriod;
+        }
+
+        mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, buffer2->handle, -1);
+        const auto setExpectedPresentTime = [&]() -> std::optional<ClockMonotonicTimestamp> {
+            if (!framesDelay.has_value()) {
+                return ComposerClientWriter::kNoTimestamp;
+            } else if (*framesDelay == 0) {
+                return ClockMonotonicTimestamp{0};
+            }
+            return ClockMonotonicTimestamp{expectedPresentTime};
+        }();
+
+        const sp<::android::Fence> presentFence2 = presentAndGetFence(setExpectedPresentTime);
+        presentFence2->waitForever(LOG_TAG);
+
+        const auto actualPresentTime = presentFence2->getSignalTime();
+        const auto presentError = std::abs(expectedPresentTime - actualPresentTime);
+        EXPECT_LE(presentError, vsyncPeriod / 2);
+
+        ASSERT_TRUE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF).isOk());
+    }
+
     // clang-format off
     const std::array<float, 16> kIdentity = {{
             1.0f, 0.0f, 0.0f, 0.0f,
@@ -1462,19 +1551,19 @@
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, VALIDATE_DISPLAY) {
-    mWriter.validateDisplay(mPrimaryDisplay);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
     execute();
 }
 
 TEST_P(GraphicsComposerAidlCommandTest, ACCEPT_DISPLAY_CHANGES) {
-    mWriter.validateDisplay(mPrimaryDisplay);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
     mWriter.acceptDisplayChanges(mPrimaryDisplay);
     execute();
 }
 
 // TODO(b/208441745) fix the test failure
 TEST_P(GraphicsComposerAidlCommandTest, PRESENT_DISPLAY) {
-    mWriter.validateDisplay(mPrimaryDisplay);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
     mWriter.presentDisplay(mPrimaryDisplay);
     execute();
 }
@@ -1523,7 +1612,7 @@
         mWriter.setLayerBuffer(mPrimaryDisplay, layer, 0, handle, -1);
         mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN);
 
-        mWriter.validateDisplay(mPrimaryDisplay);
+        mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
         execute();
         std::vector<int64_t> layers;
         std::vector<Composition> types;
@@ -1570,7 +1659,7 @@
     mWriter.setLayerBlendMode(mPrimaryDisplay, layer, BlendMode::NONE);
     mWriter.setLayerSurfaceDamage(mPrimaryDisplay, layer, std::vector<Rect>(1, displayFrame));
     mWriter.setLayerDataspace(mPrimaryDisplay, layer, Dataspace::UNKNOWN);
-    mWriter.validateDisplay(mPrimaryDisplay);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
 
     execute();
     std::vector<int64_t> layers;
@@ -1587,7 +1676,7 @@
     execute();
 
     mWriter.setLayerCursorPosition(mPrimaryDisplay, layer, 0, 0);
-    mWriter.validateDisplay(mPrimaryDisplay);
+    mWriter.validateDisplay(mPrimaryDisplay, ComposerClientWriter::kNoTimestamp);
     mWriter.presentDisplay(mPrimaryDisplay);
     execute();
 }
@@ -1947,6 +2036,18 @@
     }
 }
 
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_NoTimestamp) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(std::nullopt));
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_0) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(0));
+}
+
+TEST_P(GraphicsComposerAidlCommandTest, expectedPresentTime_5) {
+    ASSERT_NO_FATAL_FAILURE(Test_expectedPresentTime(5));
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandTest);
 INSTANTIATE_TEST_SUITE_P(
         PerInstance, GraphicsComposerAidlCommandTest,
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
index bd03673..dc15ea0 100644
--- a/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/ComposerClientWriter.h
@@ -63,6 +63,8 @@
 
 class ComposerClientWriter {
   public:
+    static constexpr std::optional<ClockMonotonicTimestamp> kNoTimestamp = std::nullopt;
+
     ComposerClientWriter() { reset(); }
 
     virtual ~ComposerClientWriter() { reset(); }
@@ -95,10 +97,18 @@
                 getBuffer(slot, buffer, releaseFence));
     }
 
-    void validateDisplay(int64_t display) { getDisplayCommand(display).validateDisplay = true; }
+    void validateDisplay(int64_t display,
+                         std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        auto& command = getDisplayCommand(display);
+        command.expectedPresentTime = expectedPresentTime;
+        command.validateDisplay = true;
+    }
 
-    void presentOrvalidateDisplay(int64_t display) {
-        getDisplayCommand(display).presentOrValidateDisplay = true;
+    void presentOrvalidateDisplay(int64_t display,
+                                  std::optional<ClockMonotonicTimestamp> expectedPresentTime) {
+        auto& command = getDisplayCommand(display);
+        command.expectedPresentTime = expectedPresentTime;
+        command.presentOrValidateDisplay = true;
     }
 
     void acceptDisplayChanges(int64_t display) {