Add unittests for GpuMemTracer

This change adds some unittests for the GpuMemTracer module to verify
that the producer indeed works.

Bug: 164194338
Test: atest gpuservice_unittest:GpuMemTracerTest
Change-Id: I9f570567310f23261b43c85ab8cdc3ede8717f09
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
index 919fed3..9f951d3 100644
--- a/services/gpuservice/tracing/Android.bp
+++ b/services/gpuservice/tracing/Android.bp
@@ -21,10 +21,13 @@
         "libgpumem",
         "libbase",
         "liblog",
+        "libprotobuf-cpp-lite",
+        "libprotoutil",
         "libutils",
     ],
     static_libs: [
         "libperfetto_client_experimental",
+        "perfetto_trace_protos",
     ],
     export_include_dirs: ["include"],
     export_static_lib_headers: [
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
index 000cf27..584498e 100644
--- a/services/gpuservice/tracing/GpuMemTracer.cpp
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -22,6 +22,7 @@
 
 #include <gpumem/GpuMem.h>
 #include <perfetto/trace/android/gpu_mem_event.pbzero.h>
+#include <perfetto/trace/trace.pb.h>
 #include <unistd.h>
 
 #include <thread>
@@ -44,9 +45,51 @@
     args.backends = perfetto::kSystemBackend;
     perfetto::Tracing::Initialize(args);
     registerDataSource();
-    std::thread tracerThread(&GpuMemTracer::threadLoop, this);
+    std::thread tracerThread(&GpuMemTracer::threadLoop, this, true);
     pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread");
     tracerThread.detach();
+    tracerThreadCount++;
+}
+
+void GpuMemTracer::initializeForTest(std::shared_ptr<GpuMem> gpuMem) {
+    mGpuMem = gpuMem;
+    perfetto::TracingInitArgs args;
+    args.backends = perfetto::kInProcessBackend;
+    perfetto::Tracing::Initialize(args);
+    registerDataSource();
+    std::thread tracerThread(&GpuMemTracer::threadLoop, this, false);
+    pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThreadForTest");
+    tracerThread.detach();
+    tracerThreadCount++;
+}
+
+std::vector<perfetto::protos::TracePacket> GpuMemTracer::readGpuMemTotalPacketsForTestBlocking(
+        perfetto::TracingSession* tracingSession) {
+    std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+    perfetto::protos::Trace trace;
+    trace.ParseFromArray(raw_trace.data(), int(raw_trace.size()));
+
+    std::vector<perfetto::protos::TracePacket> packets;
+    for (const auto& packet : trace.packet()) {
+        if (!packet.has_gpu_mem_total_event()) {
+            continue;
+        }
+        packets.emplace_back(packet);
+    }
+    return packets;
+}
+
+// Each tracing session can be used for a single block of Start -> Stop.
+std::unique_ptr<perfetto::TracingSession> GpuMemTracer::getTracingSessionForTest() {
+    perfetto::TraceConfig cfg;
+    cfg.set_duration_ms(500);
+    cfg.add_buffers()->set_size_kb(1024);
+    auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+    ds_cfg->set_name(GpuMemTracer::kGpuMemDataSource);
+
+    auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+    tracingSession->Setup(cfg);
+    return tracingSession;
 }
 
 void GpuMemTracer::registerDataSource() {
@@ -55,8 +98,8 @@
     GpuMemDataSource::Register(dsd);
 }
 
-void GpuMemTracer::threadLoop() {
-    while (true) {
+void GpuMemTracer::threadLoop(bool infiniteLoop) {
+    do {
         {
             std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
             while (!sTraceStarted) {
@@ -68,7 +111,11 @@
             std::lock_guard<std::mutex> lock(GpuMemTracer::sTraceMutex);
             sTraceStarted = false;
         }
-    }
+    } while (infiniteLoop);
+
+    // Thread loop is exiting. Reduce the tracerThreadCount to reflect the number of active threads
+    // in the wait loop.
+    tracerThreadCount--;
 }
 
 void GpuMemTracer::traceInitialCounters() {
diff --git a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
index 40deb4c..ae871f1 100644
--- a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
+++ b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
@@ -20,6 +20,10 @@
 
 #include <mutex>
 
+namespace perfetto::protos {
+class TracePacket;
+}
+
 namespace android {
 
 class GpuMem;
@@ -45,16 +49,37 @@
     // perfetto::kInProcessBackend in tests.
     void registerDataSource();
 
+    // TODO(b/175904796): Refactor gpuservice lib to include perfetto lib and move the test
+    // functions into the unittests.
+    // Functions only used for testing with in-process backend. These functions require the static
+    // perfetto lib to be linked. If the tests have a perfetto linked, while libgpumemtracer.so also
+    // has one linked, they will both use different static states maintained in perfetto. Since the
+    // static perfetto states are not shared, tracing sessions created in the unit test are not
+    // recognized by GpuMemTracer. As a result, we cannot use any of the perfetto functions from
+    // this class, which defeats the purpose of the unit test. To solve this, we restrict all
+    // tracing functionality to this class, while the unit test validates the data.
+    // Sets up the perfetto in-process backend and calls into registerDataSource.
+    void initializeForTest(std::shared_ptr<GpuMem>);
+    // Creates a tracing session with in process backend, for testing.
+    std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest();
+    // Read and filter the gpu memory packets from the created trace.
+    std::vector<perfetto::protos::TracePacket> readGpuMemTotalPacketsForTestBlocking(
+            perfetto::TracingSession* tracingSession);
+
     static constexpr char kGpuMemDataSource[] = "android.gpu.memory";
     static std::condition_variable sCondition;
     static std::mutex sTraceMutex;
     static bool sTraceStarted;
 
 private:
-    void traceInitialCounters();
-    void threadLoop();
+    // Friend class for testing
+    friend class GpuMemTracerTest;
 
+    void threadLoop(bool infiniteLoop);
+    void traceInitialCounters();
     std::shared_ptr<GpuMem> mGpuMem;
+    // Count of how many tracer threads are currently active. Useful for testing.
+    std::atomic<int32_t> tracerThreadCount = 0;
 };
 
 } // namespace android