[ANativeWindow] Add stub for ANativeWindow_setDequeueTimeout

HWUI and media both require setting a dequeue timeout so that dequeue
calls don't hang.

Bug: 137012798
Test: libnativewindow_test
Change-Id: Ic85b07096d490918ae4a722516b8c4b6cb0ab678
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 3b195f7..fecfa19 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -284,3 +284,7 @@
     int success = window->perform(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START, &time);
     return success < 0 ? success : time;
 }
+
+int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) {
+    return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout);
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 3ddd549..9798c2f 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -48,4 +48,13 @@
  */
 int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window);
 
+/**
+ * Sets a timeout in nanoseconds for dequeue calls. All subsequent dequeue calls
+ * made by the window will return -ETIMEDOUT after the timeout if the dequeue
+ * takes too long.
+ *
+ * \return NO_ERROR on succes, -errno on error.
+ */
+int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout);
+
 __END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index b7ae28a..8f85007 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -240,6 +240,7 @@
     NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
     NATIVE_WINDOW_SET_AUTO_PREROTATION            = 35,
     NATIVE_WINDOW_GET_LAST_DEQUEUE_START          = 36,    /* private */
+    NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT             = 37,    /* private */
     // clang-format on
 };
 
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 33c6400..b741faa 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -40,6 +40,7 @@
     ANativeWindow_setBuffersGeometry;
     ANativeWindow_setBuffersTimestamp; # vndk
     ANativeWindow_setBuffersTransform;
+    ANativeWindow_setDequeueTimeout; # apex # introduced=30
     ANativeWindow_setSharedBufferMode; # vndk
     ANativeWindow_setSwapInterval; # vndk
     ANativeWindow_setUsage; # vndk
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 947217d..4d2b8c8 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -138,3 +138,31 @@
     EXPECT_GT(result, 0);
     EXPECT_EQ(result, mWindow->getLastDequeueStartTime());
 }
+
+TEST_F(ANativeWindowTest, setDequeueTimeout_causesDequeueTimeout) {
+    nsecs_t timeout = milliseconds_to_nanoseconds(100);
+    int result = ANativeWindow_setDequeueTimeout(mWindow.get(), timeout);
+    EXPECT_EQ(0, result);
+
+    // The two dequeues should not timeout...
+    ANativeWindowBuffer* buffer;
+    int fd;
+    int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+    close(fd);
+    EXPECT_EQ(0, dequeueResult);
+    int queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1);
+    EXPECT_EQ(0, queueResult);
+    dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+    close(fd);
+    EXPECT_EQ(0, dequeueResult);
+    queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1);
+    EXPECT_EQ(0, queueResult);
+
+    // ...but the third one should since the queue depth is too deep.
+    nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+    dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+    nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+    close(fd);
+    EXPECT_EQ(TIMED_OUT, dequeueResult);
+    EXPECT_GE(end - start, timeout);
+}