Add Shared timeline jank classification listener (1/2)

Adds the ability to register a listener that gets informed about
SF' jank classifications via the TransactionCompleted interface

Bug: 17475548
Test: FrameTimelineTest
Test: Register listener, ensure data flows back
Change-Id: Ie42c508da605c03569eadab6ab18b7315b35d247
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 69f7894..2dacae1 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "ITransactionCompletedListener"
 //#define LOG_NDEBUG 0
 
+#include <gui/LayerState.h>
+#include <gui/ISurfaceComposer.h>
 #include <gui/ITransactionCompletedListener.h>
 
 namespace android {
@@ -90,61 +92,63 @@
     return err;
 }
 
-status_t SurfaceStats::writeToParcel(Parcel* output) const {
-    status_t err = output->writeStrongBinder(surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = output->writeInt64(acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    if (previousReleaseFence) {
-        err = output->writeBool(true);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        err = output->write(*previousReleaseFence);
-    } else {
-        err = output->writeBool(false);
-    }
-    err = output->writeUint32(transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+JankData::JankData() :
+        frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+        jankType(JankType::None) {
+}
 
-    err = output->writeParcelable(eventStats);
-    return err;
+status_t JankData::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeInt64, frameVsyncId);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankType));
+    return NO_ERROR;
+}
+
+status_t JankData::readFromParcel(const Parcel* input) {
+    SAFE_PARCEL(input->readInt64, &frameVsyncId);
+    int32_t jankTypeInt;
+    SAFE_PARCEL(input->readInt32, &jankTypeInt);
+    jankType = static_cast<JankType>(jankTypeInt);
+    return NO_ERROR;
+}
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
+    SAFE_PARCEL(output->writeInt64, acquireTime);
+    if (previousReleaseFence) {
+        SAFE_PARCEL(output->writeBool, true);
+        SAFE_PARCEL(output->write, *previousReleaseFence);
+    } else {
+        SAFE_PARCEL(output->writeBool, false);
+    }
+    SAFE_PARCEL(output->writeUint32, transformHint);
+    SAFE_PARCEL(output->writeParcelable, eventStats);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
+    for (const auto& data : jankData) {
+        SAFE_PARCEL(output->writeParcelable, data);
+    }
+    return NO_ERROR;
 }
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
-    status_t err = input->readStrongBinder(&surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = input->readInt64(&acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
+    SAFE_PARCEL(input->readInt64, &acquireTime);
     bool hasFence = false;
-    err = input->readBool(&hasFence);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readBool, &hasFence);
     if (hasFence) {
         previousReleaseFence = new Fence();
-        err = input->read(*previousReleaseFence);
-        if (err != NO_ERROR) {
-            return err;
-        }
+        SAFE_PARCEL(input->read, *previousReleaseFence);
     }
-    err = input->readUint32(&transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readUint32, &transformHint);
+    SAFE_PARCEL(input->readParcelable, &eventStats);
 
-    err = input->readParcelable(&eventStats);
-    return err;
+    int32_t jankData_size = 0;
+    SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize());
+    for (int i = 0; i < jankData_size; i++) {
+        JankData data;
+        SAFE_PARCEL(input->readParcelable, &data);
+        jankData.push_back(data);
+    }
+    return NO_ERROR;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47a08ab..9ed7d1c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -125,6 +125,9 @@
     return DefaultComposerClient::getComposerClient();
 }
 
+JankDataListener::~JankDataListener() {
+}
+
 // ---------------------------------------------------------------------------
 
 // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -174,6 +177,23 @@
     return callbackId;
 }
 
+void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
+                                                   sp<SurfaceControl> surfaceControl) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mJankListeners.insert({surfaceControl->getHandle(), listener});
+}
+
+void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto it = mJankListeners.begin(); it != mJankListeners.end();) {
+        if (it->second == listener) {
+            it = mJankListeners.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
         const std::unordered_set<CallbackId>& callbackIds) {
@@ -189,6 +209,7 @@
 
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
     std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+    std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
@@ -204,6 +225,7 @@
          * sp<SurfaceControl> that could possibly exist for the callbacks.
          */
         callbacksMap = mCallbacks;
+        jankListenersMap = mJankListeners;
         for (const auto& transactionStats : listenerStats.transactionStats) {
             for (auto& callbackId : transactionStats.callbackIds) {
                 mCallbacks.erase(callbackId);
@@ -236,6 +258,13 @@
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                              surfaceControlStats);
         }
+        for (const auto& surfaceStats : transactionStats.surfaceStats) {
+            if (surfaceStats.jankData.empty()) continue;
+            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
+                    it != jankListenersMap.end(); it++) {
+                it->second->onJankDataAvailable(surfaceStats.jankData);
+            }
+        }
     }
 }
 
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index c58634b..26b3840 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "JankInfo.h"
+
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
@@ -57,6 +59,27 @@
     nsecs_t dequeueReadyTime;
 };
 
+/**
+ * Jank information representing SurfaceFlinger's jank classification about frames for a specific
+ * surface.
+ */
+class JankData : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    JankData();
+    JankData(int64_t frameVsyncId, JankType jankType)
+          : frameVsyncId(frameVsyncId),
+            jankType(jankType) {}
+
+    // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
+    int64_t frameVsyncId;
+
+    // The type of jank occurred
+    JankType jankType;
+};
+
 class SurfaceStats : public Parcelable {
 public:
     status_t writeToParcel(Parcel* output) const override;
@@ -64,18 +87,21 @@
 
     SurfaceStats() = default;
     SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
-                 uint32_t hint, FrameEventHistoryStats frameEventStats)
+                 uint32_t hint, FrameEventHistoryStats frameEventStats,
+                 std::vector<JankData> jankData)
           : surfaceControl(sc),
             acquireTime(time),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
-            eventStats(frameEventStats) {}
+            eventStats(frameEventStats),
+            jankData(std::move(jankData)) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
     FrameEventHistoryStats eventStats;
+    std::vector<JankData> jankData;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2eb97f2..f1845ee 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -619,6 +619,12 @@
 
 // ---------------------------------------------------------------------------
 
+class JankDataListener : public VirtualLightRefBase {
+public:
+    virtual ~JankDataListener() = 0;
+    virtual void onJankDataAvailable(const std::vector<JankData>& jankData) = 0;
+};
+
 class TransactionCompletedListener : public BnTransactionCompletedListener {
     TransactionCompletedListener();
 
@@ -637,6 +643,7 @@
     };
 
     std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+    std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
 
 public:
     static sp<TransactionCompletedListener> getInstance();
@@ -652,6 +659,18 @@
     void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
                                       const std::unordered_set<CallbackId>& callbackIds);
 
+    /*
+     * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
+     * surface. Jank classifications arrive as part of the transaction callbacks about previous
+     * frames submitted to this Surface.
+     */
+    void addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl);
+
+    /**
+     * Removes a jank listener previously added to addJankCallback.
+     */
+    void removeJankListener(const sp<JankDataListener>& listener);
+
     // Overrides BnTransactionCompletedListener's onTransactionCompleted
     void onTransactionCompleted(ListenerStats stats) override;
 };