Choreographer: add new NDK APIs for callback data.

Bug: 198191648
Bug: 168552873
Test: atest ChoreographerNativeTest
Change-Id: I2472acb7b724354b657fc89983fade7ced5eb7eb
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index b743f49..0389e57 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -39,6 +39,12 @@
  */
 typedef struct AChoreographer AChoreographer;
 
+struct AChoreographerFrameCallbackData;
+/**
+ * Opaque type that provides access to an AChoreographerFrameCallbackData object.
+ */
+typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
+
 /**
  * Prototype of the function that is called when a new frame is being rendered.
  * It's passed the time that the frame is being rendered as nanoseconds in the
@@ -60,6 +66,14 @@
 typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
 
 /**
+ * Prototype of the function that is called when a new frame is being rendered.
+ * It's passed the frame data that should not outlive the callback, as well as the data pointer
+ * provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_extendedFrameCallback)(
+        const AChoreographerFrameCallbackData* callbackData, void* data);
+
+/**
  * Prototype of the function that is called when the display refresh rate
  * changes. It's passed the new vsync period in nanoseconds, as well as the data
  * pointer provided by the application that registered a callback.
@@ -111,6 +125,14 @@
                                                uint32_t delayMillis) __INTRODUCED_IN(29);
 
 /**
+ * Posts a callback to run on the next frame. The data pointer provided will
+ * be passed to the callback function when it's called.
+ */
+void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
+                                        AChoreographer_extendedFrameCallback callback, void* data)
+        __INTRODUCED_IN(33);
+
+/**
  * Registers a callback to be run when the display refresh rate changes. The
  * data pointer provided will be passed to the callback function when it's
  * called. The same callback may be registered multiple times, provided that a
@@ -160,6 +182,42 @@
                                                   AChoreographer_refreshRateCallback, void* data)
         __INTRODUCED_IN(30);
 
+/**
+ * The time in nanoseconds when the frame started being rendered.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+        const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The number of possible frame timelines.
+ */
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+        const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * Get index of the platform-preferred FrameTimeline.
+ */
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+        const AChoreographerFrameCallbackData* data) __INTRODUCED_IN(33);
+
+/**
+ * The vsync ID token used to map Choreographer data.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+        const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index is expected to be presented.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+        const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
+/**
+ * The time in nanoseconds which the frame at given index needs to be ready by.
+ */
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+        const AChoreographerFrameCallbackData* data, size_t index) __INTRODUCED_IN(33);
+
 __END_DECLS
 
 #endif // ANDROID_CHOREOGRAPHER_H
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index ba71960..4c4a34f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -77,6 +77,7 @@
 struct FrameCallback {
     AChoreographer_frameCallback callback;
     AChoreographer_frameCallback64 callback64;
+    AChoreographer_extendedFrameCallback extendedCallback;
     void* data;
     nsecs_t dueTime;
 
@@ -95,6 +96,27 @@
 
 class Choreographer;
 
+/**
+ * Implementation of AChoreographerFrameCallbackData.
+ */
+struct ChoreographerFrameCallbackDataImpl {
+    struct FrameTimeline {
+        int64_t vsyncId{0};
+        int64_t expectedPresentTimeNanos{0};
+        int64_t deadlineNanos{0};
+    };
+
+    int64_t frameTimeNanos{0};
+
+    size_t frameTimelinesLength;
+
+    std::vector<FrameTimeline> frameTimelines;
+
+    size_t preferredFrameTimelineIndex;
+
+    const Choreographer* choreographer;
+};
+
 struct {
     std::mutex lock;
     std::vector<Choreographer*> ptrs GUARDED_BY(lock);
@@ -107,7 +129,9 @@
 public:
     explicit Choreographer(const sp<Looper>& looper) EXCLUDES(gChoreographers.lock);
     void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
-                                  AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
+                                  AChoreographer_frameCallback64 cb64,
+                                  AChoreographer_extendedFrameCallback extendedCallback, void* data,
+                                  nsecs_t delay);
     void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data)
             EXCLUDES(gChoreographers.lock);
     void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
@@ -130,6 +154,7 @@
     int64_t getVsyncId() const;
     int64_t getFrameDeadline() const;
     int64_t getFrameInterval() const;
+    bool inCallback() const;
 
 private:
     Choreographer(const Choreographer&) = delete;
@@ -145,6 +170,8 @@
 
     void scheduleCallbacks();
 
+    ChoreographerFrameCallbackDataImpl createFrameCallbackData(nsecs_t timestamp) const;
+
     std::mutex mLock;
     // Protected by mLock
     std::priority_queue<FrameCallback> mFrameCallbacks;
@@ -152,6 +179,7 @@
 
     nsecs_t mLatestVsyncPeriod = -1;
     VsyncEventData mLastVsyncEventData;
+    bool mInCallback = false;
 
     const sp<Looper> mLooper;
     const std::thread::id mThreadId;
@@ -211,10 +239,12 @@
     }
 }
 
-void Choreographer::postFrameCallbackDelayed(
-        AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
+void Choreographer::postFrameCallbackDelayed(AChoreographer_frameCallback cb,
+                                             AChoreographer_frameCallback64 cb64,
+                                             AChoreographer_extendedFrameCallback extendedCallback,
+                                             void* data, nsecs_t delay) {
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    FrameCallback callback{cb, cb64, data, now + delay};
+    FrameCallback callback{cb, cb64, extendedCallback, data, now + delay};
     {
         std::lock_guard<std::mutex> _l{mLock};
         mFrameCallbacks.push(callback);
@@ -370,7 +400,15 @@
     }
     mLastVsyncEventData = vsyncEventData;
     for (const auto& cb : callbacks) {
-        if (cb.callback64 != nullptr) {
+        if (cb.extendedCallback != nullptr) {
+            const ChoreographerFrameCallbackDataImpl frameCallbackData =
+                    createFrameCallbackData(timestamp);
+            mInCallback = true;
+            cb.extendedCallback(reinterpret_cast<const AChoreographerFrameCallbackData*>(
+                                        &frameCallbackData),
+                                cb.data);
+            mInCallback = false;
+        } else if (cb.callback64 != nullptr) {
             cb.callback64(timestamp, cb.data);
         } else if (cb.callback != nullptr) {
             cb.callback(timestamp, cb.data);
@@ -379,8 +417,8 @@
 }
 
 void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
-    ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.",
-            this, to_string(displayId).c_str(), toString(connected));
+    ALOGV("choreographer %p ~ received hotplug event (displayId=%s, connected=%s), ignoring.", this,
+          to_string(displayId).c_str(), toString(connected));
 }
 
 void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
@@ -399,15 +437,15 @@
 
 void Choreographer::handleMessage(const Message& message) {
     switch (message.what) {
-    case MSG_SCHEDULE_CALLBACKS:
-        scheduleCallbacks();
-        break;
-    case MSG_SCHEDULE_VSYNC:
-        scheduleVsync();
-        break;
-    case MSG_HANDLE_REFRESH_RATE_UPDATES:
-        handleRefreshRateUpdates();
-        break;
+        case MSG_SCHEDULE_CALLBACKS:
+            scheduleCallbacks();
+            break;
+        case MSG_SCHEDULE_VSYNC:
+            scheduleVsync();
+            break;
+        case MSG_HANDLE_REFRESH_RATE_UPDATES:
+            handleRefreshRateUpdates();
+            break;
     }
 }
 
@@ -423,6 +461,22 @@
     return mLastVsyncEventData.frameInterval;
 }
 
+bool Choreographer::inCallback() const {
+    return mInCallback;
+}
+
+ChoreographerFrameCallbackDataImpl Choreographer::createFrameCallbackData(nsecs_t timestamp) const {
+    std::vector<ChoreographerFrameCallbackDataImpl::FrameTimeline> frameTimelines;
+    frameTimelines.push_back({.vsyncId = mLastVsyncEventData.id,
+                              .expectedPresentTimeNanos = mLastVsyncEventData.expectedPresentTime,
+                              .deadlineNanos = mLastVsyncEventData.deadlineTimestamp});
+    return {.frameTimeNanos = timestamp,
+            .frameTimelinesLength = 1,
+            .preferredFrameTimelineIndex = 0,
+            .frameTimelines = frameTimelines,
+            .choreographer = this};
+}
+
 } // namespace android
 using namespace android;
 
@@ -435,6 +489,12 @@
     return reinterpret_cast<const Choreographer*>(choreographer);
 }
 
+static inline const ChoreographerFrameCallbackDataImpl*
+AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(
+        const AChoreographerFrameCallbackData* data) {
+    return reinterpret_cast<const ChoreographerFrameCallbackDataImpl*>(data);
+}
+
 // Glue for private C api
 namespace android {
 void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) {
@@ -487,6 +547,11 @@
                                                     void* data, uint32_t delayMillis) {
     return AChoreographer_postFrameCallbackDelayed64(choreographer, callback, data, delayMillis);
 }
+void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
+                                                   AChoreographer_extendedFrameCallback callback,
+                                                   void* data) {
+    return AChoreographer_postExtendedFrameCallback(choreographer, callback, data);
+}
 void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
                                                      AChoreographer_refreshRateCallback callback,
                                                      void* data) {
@@ -497,6 +562,30 @@
                                                        void* data) {
     return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data);
 }
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos(
+        const AChoreographerFrameCallbackData* data) {
+    return AChoreographerFrameCallbackData_getFrameTimeNanos(data);
+}
+size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength(
+        const AChoreographerFrameCallbackData* data) {
+    return AChoreographerFrameCallbackData_getFrameTimelinesLength(data);
+}
+size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex(
+        const AChoreographerFrameCallbackData* data) {
+    return AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(data);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    return AChoreographerFrameCallbackData_getFrameTimelineVsyncId(data, index);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    return AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(data, index);
+}
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    return AChoreographerFrameCallbackData_getFrameTimelineDeadline(data, index);
+}
 
 int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) {
     return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
@@ -523,24 +612,32 @@
 }
 
 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
-        AChoreographer_frameCallback callback, void* data) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            callback, nullptr, data, 0);
+                                      AChoreographer_frameCallback callback, void* data) {
+    AChoreographer_to_Choreographer(choreographer)
+            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, 0);
 }
 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
-        AChoreographer_frameCallback callback, void* data, long delayMillis) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            callback, nullptr, data, ms2ns(delayMillis));
+                                             AChoreographer_frameCallback callback, void* data,
+                                             long delayMillis) {
+    AChoreographer_to_Choreographer(choreographer)
+            ->postFrameCallbackDelayed(callback, nullptr, nullptr, data, ms2ns(delayMillis));
+}
+void AChoreographer_postExtendedFrameCallback(AChoreographer* choreographer,
+                                              AChoreographer_extendedFrameCallback callback,
+                                              void* data) {
+    AChoreographer_to_Choreographer(choreographer)
+            ->postFrameCallbackDelayed(nullptr, nullptr, callback, data, 0);
 }
 void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
-        AChoreographer_frameCallback64 callback, void* data) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            nullptr, callback, data, 0);
+                                        AChoreographer_frameCallback64 callback, void* data) {
+    AChoreographer_to_Choreographer(choreographer)
+            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, 0);
 }
 void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
-        AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            nullptr, callback, data, ms2ns(delayMillis));
+                                               AChoreographer_frameCallback64 callback, void* data,
+                                               uint32_t delayMillis) {
+    AChoreographer_to_Choreographer(choreographer)
+            ->postFrameCallbackDelayed(nullptr, callback, nullptr, data, ms2ns(delayMillis));
 }
 void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
                                                 AChoreographer_refreshRateCallback callback,
@@ -553,6 +650,58 @@
     AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
 }
 
+int64_t AChoreographerFrameCallbackData_getFrameTimeNanos(
+        const AChoreographerFrameCallbackData* data) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    return frameCallbackData->frameTimeNanos;
+}
+size_t AChoreographerFrameCallbackData_getFrameTimelinesLength(
+        const AChoreographerFrameCallbackData* data) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    return frameCallbackData->frameTimelinesLength;
+}
+size_t AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex(
+        const AChoreographerFrameCallbackData* data) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    return frameCallbackData->preferredFrameTimelineIndex;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineVsyncId(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->frameTimelines[index].vsyncId;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->frameTimelines[index].expectedPresentTimeNanos;
+}
+int64_t AChoreographerFrameCallbackData_getFrameTimelineDeadline(
+        const AChoreographerFrameCallbackData* data, size_t index) {
+    const ChoreographerFrameCallbackDataImpl* frameCallbackData =
+            AChoreographerFrameCallbackData_to_ChoreographerFrameCallbackDataImpl(data);
+    LOG_ALWAYS_FATAL_IF(!frameCallbackData->choreographer->inCallback(),
+                        "Data is only valid in callback");
+    LOG_ALWAYS_FATAL_IF(index >= frameCallbackData->frameTimelinesLength, "Index out of bounds");
+    return frameCallbackData->frameTimelines[index].deadlineNanos;
+}
+
 AChoreographer* AChoreographer_create() {
     Choreographer* choreographer = new Choreographer(nullptr);
     status_t result = choreographer->initialize();
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 7d25ce8..6e90853 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -63,11 +63,26 @@
 void AChoreographer_routePostFrameCallbackDelayed64(AChoreographer* choreographer,
                                                     AChoreographer_frameCallback64 callback,
                                                     void* data, uint32_t delayMillis);
+void AChoreographer_routePostExtendedFrameCallback(AChoreographer* choreographer,
+                                                   AChoreographer_extendedFrameCallback callback,
+                                                   void* data);
 void AChoreographer_routeRegisterRefreshRateCallback(AChoreographer* choreographer,
                                                      AChoreographer_refreshRateCallback callback,
                                                      void* data);
 void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreographer,
                                                        AChoreographer_refreshRateCallback callback,
                                                        void* data);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimeNanos(
+        const AChoreographerFrameCallbackData* data);
+size_t AChoreographerFrameCallbackData_routeGetFrameTimelinesLength(
+        const AChoreographerFrameCallbackData* data);
+size_t AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex(
+        const AChoreographerFrameCallbackData* data);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId(
+        const AChoreographerFrameCallbackData* data, size_t index);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime(
+        const AChoreographerFrameCallbackData* data, size_t index);
+int64_t AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline(
+        const AChoreographerFrameCallbackData* data, size_t index);
 
 } // namespace android
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 9ed4915..b4a70e8 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -7,6 +7,13 @@
     AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
     AChoreographer_registerRefreshRateCallback; # apex # introduced=30
     AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
+    AChoreographer_postExtendedFrameCallback; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimeNanos; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelinesLength; # apex # introduced=33
+    AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineVsyncId; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentTime; # apex # introduced=33
+    AChoreographerFrameCallbackData_getFrameTimelineDeadline; # apex # introduced=33
     AChoreographer_create; # apex # introduced=30
     AChoreographer_destroy; # apex # introduced=30
     AChoreographer_getFd; # apex # introduced=30
@@ -28,6 +35,13 @@
       android::AChoreographer_routePostFrameCallbackDelayed64*;
       android::AChoreographer_routeRegisterRefreshRateCallback*;
       android::AChoreographer_routeUnregisterRefreshRateCallback*;
+      android::AChoreographer_routePostExtendedFrameCallback*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimeNanos*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimelinesLength*;
+      android::AChoreographerFrameCallbackData_routeGetPreferredFrameTimelineIndex*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimelineVsyncId*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimelineExpectedPresentTime*;
+      android::AChoreographerFrameCallbackData_routeGetFrameTimelineDeadline*;
       android::AChoreographer_signalRefreshRateCallbacks*;
       android::AChoreographer_getVsyncId*;
       android::AChoreographer_getFrameDeadline*;