[ANativeWindow] Add apex stub for getLastDequeueStartTime

Also adding private query64 hook so that timing queries can have
nanosecond precision. Otherwise with a 32-bit width we can only have
millisecond precision for timestamps and microsecond precision for time
intervals, and really we shouldn't need to be less precise if we can
help it.

Bug: 137012798
Test: libnativewindow_test
Change-Id: I62233a588eee80f7ea70b74824c8e47461a3be81
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 5c91d58..3b195f7 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -278,3 +278,9 @@
 int ANativeWindow_getLastQueueDuration(ANativeWindow* window) {
     return query(window, NATIVE_WINDOW_LAST_QUEUE_DURATION);
 }
+
+int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) {
+    int64_t time;
+    int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time);
+    return success < 0 ? success : time;
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 82ff50d..3ddd549 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -39,4 +39,13 @@
  */
 int ANativeWindow_getLastQueueDuration(ANativeWindow* window);
 
+/**
+ * Retrieves the system time in nanoseconds when the last time a buffer
+ * was dequeued.
+ *
+ * \return a negative value on error, otherwise returns the duration in
+ * nanoseconds.
+ */
+int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window);
+
 __END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 78354bb..b7ae28a 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -93,7 +93,6 @@
      */
     NATIVE_WINDOW_CONCRETE_TYPE = 5,
 
-
     /*
      * Default width and height of ANativeWindow buffers, these are the
      * dimensions of the window buffers irrespective of the
@@ -240,6 +239,7 @@
     NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA   = 33,
     NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
     NATIVE_WINDOW_SET_AUTO_PREROTATION            = 35,
+    NATIVE_WINDOW_GET_LAST_DEQUEUE_START          = 36,    /* private */
     // clang-format on
 };
 
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index b8b45ae..33c6400 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -23,6 +23,7 @@
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getLastDequeueDuration; # apex # introduced=30
+    ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
     ANativeWindow_getLastQueueDuration; # apex # introduced=30
     ANativeWindow_getWidth;
     ANativeWindow_lock;
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 9b358da..947217d 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -39,6 +39,9 @@
 
     // Exposes the internal last queue duration that's stored on the Surface.
     nsecs_t getLastQueueDuration() const { return mLastQueueDuration; }
+
+    // Exposes the internal last dequeue start time that's stored on the Surface.
+    nsecs_t getLastDequeueStartTime() const { return mLastDequeueStartTime; }
 };
 
 class ANativeWindowTest : public ::testing::Test {
@@ -117,3 +120,21 @@
     EXPECT_GT(result, 0);
     EXPECT_EQ(result, mWindow->getLastQueueDuration() / 1000);
 }
+
+TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) {
+    int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get());
+    EXPECT_EQ(0, result);
+    EXPECT_EQ(0, mWindow->getLastQueueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) {
+    ANativeWindowBuffer* buffer;
+    int fd;
+    int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+    close(fd);
+    EXPECT_EQ(0, dequeueResult);
+
+    int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get());
+    EXPECT_GT(result, 0);
+    EXPECT_EQ(result, mWindow->getLastDequeueStartTime());
+}