Add GPU completion to FrameMetrics (2/3)

- Add SurfaceStatsCallback to TransactionCompletedListener
- Register a callback in RenderProxy to be called when we have
surface stats from SF via the BLAST callback.
- Instead of finishing a frame for frame metrics reporting
immediately, wait until BLAST callback fires, note GPU completion
time and finish frame.
- Expose GPU_COMPLETION in FrameMetrics
- Modify TOTAL_DURATION to also include GPU_COMPLETION

Test: FrameMetricsListenerTest
Fixes: 171046219
Change-Id: If4b63c6a4c49c9ce2f31410d7f33541b0e6bf594
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 27fb2a8..d41da9b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -194,6 +194,25 @@
     }
 }
 
+void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
+        sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mSurfaceStatsListeners.insert({surfaceControl->getHandle(),
+            SurfaceStatsCallbackEntry(context, cookie, listener)});
+}
+
+void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) {
+        auto [itContext, itCookie, itListener] = it->second;
+        if (itContext == context && itCookie == cookie) {
+            it = mSurfaceStatsListeners.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
         const std::unordered_set<CallbackId>& callbackIds) {
@@ -210,6 +229,7 @@
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
     std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
     std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
+    std::multimap<sp<IBinder>, SurfaceStatsCallbackEntry> surfaceListeners;
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
@@ -226,6 +246,7 @@
          */
         callbacksMap = mCallbacks;
         jankListenersMap = mJankListeners;
+        surfaceListeners = mSurfaceStatsListeners;
         for (const auto& transactionStats : listenerStats.transactionStats) {
             for (auto& callbackId : transactionStats.callbackIds) {
                 mCallbacks.erase(callbackId);
@@ -259,9 +280,16 @@
                              surfaceControlStats);
         }
         for (const auto& surfaceStats : transactionStats.surfaceStats) {
+            auto listenerRange = surfaceListeners.equal_range(surfaceStats.surfaceControl);
+            for (auto it = listenerRange.first; it != listenerRange.second; it++) {
+                auto entry = it->second;
+                entry.callback(entry.context, transactionStats.latchTime,
+                    transactionStats.presentFence, surfaceStats);
+            }
+
             if (surfaceStats.jankData.empty()) continue;
-            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
-                    it != jankListenersMap.end(); it++) {
+            auto jankRange = jankListenersMap.equal_range(surfaceStats.surfaceControl);
+            for (auto it = jankRange.first; it != jankRange.second; it++) {
                 it->second->onJankDataAvailable(surfaceStats.jankData);
             }
         }