Add listener callback to keep track of tracing state in SCC

Test: N/A
Change-Id: Iae1fe69b65a449f7e94fecaa17081022b0888c7b
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e860dff..4b91da8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4885,6 +4885,7 @@
             }
             return OK;
         }
+        case ADD_TRANSACTION_TRACE_LISTENER:
         case CAPTURE_DISPLAY_BY_ID: {
             IPCThreadState* ipc = IPCThreadState::self();
             const int uid = ipc->getCallingUid();
@@ -6230,6 +6231,17 @@
     }));
 }
 
+status_t SurfaceFlinger::addTransactionTraceListener(
+        const sp<gui::ITransactionTraceListener>& listener) {
+    if (!listener) {
+        return BAD_VALUE;
+    }
+
+    mInterceptor->addTransactionTraceListener(listener);
+
+    return NO_ERROR;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5cd9dea..d6a75c3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -596,6 +596,9 @@
     status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
                                    int64_t frameTimelineVsyncId) override;
 
+    status_t addTransactionTraceListener(
+            const sp<gui::ITransactionTraceListener>& listener) override;
+
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index d6b5338..9d705e5 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -45,9 +45,22 @@
 {
 }
 
+void SurfaceInterceptor::addTransactionTraceListener(
+        const sp<gui::ITransactionTraceListener>& listener) {
+    sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+    std::scoped_lock lock(mListenersMutex);
+
+    asBinder->linkToDeath(this);
+
+    listener->onToggled(mEnabled); // notifies of current state
+
+    mTraceToggledListeners.emplace(asBinder, listener);
+}
+
 void SurfaceInterceptor::binderDied(const wp<IBinder>& who) {
-    // TODO: Implement
-    (void)who;
+    std::scoped_lock lock(mListenersMutex);
+    mTraceToggledListeners.erase(who);
 }
 
 void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers,
@@ -57,8 +70,14 @@
         return;
     }
     ATRACE_CALL();
+    {
+        std::scoped_lock lock(mListenersMutex);
+        for (const auto& [_, listener] : mTraceToggledListeners) {
+            listener->onToggled(true);
+        }
+    }
     mEnabled = true;
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
     saveExistingDisplaysLocked(displays);
     saveExistingSurfacesLocked(layers);
 }
@@ -68,8 +87,14 @@
         return;
     }
     ATRACE_CALL();
-    std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+    {
+        std::scoped_lock lock(mListenersMutex);
+        for (const auto& [_, listener] : mTraceToggledListeners) {
+            listener->onToggled(false);
+        }
+    }
     mEnabled = false;
+    std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
     status_t err(writeProtoFileLocked());
     ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
     ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 62cc717..4908bae 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -60,6 +60,8 @@
     virtual void disable() = 0;
     virtual bool isEnabled() = 0;
 
+    virtual void addTransactionTraceListener(
+            const sp<gui::ITransactionTraceListener>& listener) = 0;
     virtual void binderDied(const wp<IBinder>& who) = 0;
 
     // Intercept display and surface transactions
@@ -99,6 +101,7 @@
     void disable() override;
     bool isEnabled() override;
 
+    void addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener) override;
     void binderDied(const wp<IBinder>& who) override;
 
     // Intercept display and surface transactions
@@ -199,6 +202,9 @@
     std::mutex mTraceMutex {};
     Trace mTrace {};
     SurfaceFlinger* const mFlinger;
+    std::mutex mListenersMutex;
+    std::map<wp<IBinder>, sp<gui::ITransactionTraceListener>> mTraceToggledListeners
+            GUARDED_BY(mListenersMutex);
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 2f3f524..e2c8a65 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -33,6 +33,7 @@
                       const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
     MOCK_METHOD0(disable, void());
     MOCK_METHOD0(isEnabled, bool());
+    MOCK_METHOD1(addTransactionTraceListener, void(const sp<gui::ITransactionTraceListener>&));
     MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
     MOCK_METHOD6(saveTransaction,
                  void(const Vector<ComposerState>&,