Merge "Amalgamated source for v27.1" into releases/v27.x
diff --git a/CHANGELOG b/CHANGELOG
index 8407784..77cb981 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -9,6 +9,11 @@
     *
 
 
+v27.1 - 2022-07-11:
+  SDK:
+    * Added an API for shutting down Perfetto.
+
+
 v27.0 - 2022-07-01:
   Tracing service and probes:
     * Fix rare crash due to watchdog timeout being too short.
diff --git a/include/perfetto/tracing/tracing.h b/include/perfetto/tracing/tracing.h
index e0f95e1..89b5efd 100644
--- a/include/perfetto/tracing/tracing.h
+++ b/include/perfetto/tracing/tracing.h
@@ -177,6 +177,19 @@
   static std::unique_ptr<TracingSession> NewTrace(
       BackendType = kUnspecifiedBackend);
 
+  // Shut down Perfetto, releasing any allocated OS resources (threads, files,
+  // sockets, etc.). Note that Perfetto cannot be reinitialized again in the
+  // same process[1]. Instead, this function is meant for shutting down all
+  // Perfetto-related code so that it can be safely unloaded, e.g., with
+  // dlclose().
+  //
+  // It is only safe to call this function when all threads recording trace
+  // events have been terminated or otherwise guaranteed to not make any further
+  // calls into Perfetto.
+  //
+  // [1] Unless static data is also cleared through other means.
+  static void Shutdown();
+
   // Uninitialize Perfetto. Only exposed for testing scenarios where it can be
   // guaranteed that no tracing sessions or other operations are happening when
   // this call is made.
diff --git a/src/tracing/internal/tracing_muxer_impl.cc b/src/tracing/internal/tracing_muxer_impl.cc
index 7f46a3a..13ba94a 100644
--- a/src/tracing/internal/tracing_muxer_impl.cc
+++ b/src/tracing/internal/tracing_muxer_impl.cc
@@ -1801,6 +1801,40 @@
   }
 }
 
+// static
+void TracingMuxerImpl::Shutdown() {
+  auto* muxer = reinterpret_cast<TracingMuxerImpl*>(instance_);
+
+  // Shutting down on the muxer thread would lead to a deadlock.
+  PERFETTO_CHECK(!muxer->task_runner_->RunsTasksOnCurrentThread());
+  muxer->DestroyStoppedTraceWritersForCurrentThread();
+
+  std::unique_ptr<base::TaskRunner> owned_task_runner(
+      muxer->task_runner_.get());
+  base::WaitableEvent shutdown_done;
+  owned_task_runner->PostTask([muxer, &shutdown_done] {
+    // Check that no consumer session is currently active on any backend.
+    // Producers will be automatically disconnected as a part of deleting the
+    // muxer below.
+    for (auto& backend : muxer->backends_) {
+      for (auto& consumer : backend.consumers) {
+        PERFETTO_CHECK(!consumer->service_);
+      }
+    }
+    // Make sure no trace writers are lingering around on the muxer thread. Note
+    // that we can't do this for any arbitrary thread in the process; it is the
+    // caller's responsibility to clean them up before shutting down Perfetto.
+    muxer->DestroyStoppedTraceWritersForCurrentThread();
+    // The task runner must be deleted outside the muxer thread. This is done by
+    // `owned_task_runner` above.
+    muxer->task_runner_.release();
+    delete muxer;
+    instance_ = TracingMuxerFake::Get();
+    shutdown_done.Notify();
+  });
+  shutdown_done.Wait();
+}
+
 TracingMuxer::~TracingMuxer() = default;
 
 static_assert(std::is_same<internal::BufferId, BufferID>::value,
diff --git a/src/tracing/internal/tracing_muxer_impl.h b/src/tracing/internal/tracing_muxer_impl.h
index 1841cd4..d0f0dac 100644
--- a/src/tracing/internal/tracing_muxer_impl.h
+++ b/src/tracing/internal/tracing_muxer_impl.h
@@ -98,6 +98,7 @@
 
   static void InitializeInstance(const TracingInitArgs&);
   static void ResetForTesting();
+  static void Shutdown();
 
   // TracingMuxer implementation.
   bool RegisterDataSource(const DataSourceDescriptor&,
diff --git a/src/tracing/test/api_integrationtest.cc b/src/tracing/test/api_integrationtest.cc
index a25ccfa..c09dfc5 100644
--- a/src/tracing/test/api_integrationtest.cc
+++ b/src/tracing/test/api_integrationtest.cc
@@ -492,6 +492,20 @@
     perfetto::Tracing::ResetForTesting();
   }
 
+  static void TearDownTestSuite() {
+    // Test shutting down Perfetto only when all other tests have been run and
+    // no more tracing code will be executed.
+    PERFETTO_CHECK(!perfetto::Tracing::IsInitialized());
+    TracingInitArgs args;
+    args.backends = perfetto::kInProcessBackend;
+    perfetto::Tracing::Initialize(args);
+    perfetto::Tracing::Shutdown();
+    PERFETTO_CHECK(!perfetto::Tracing::IsInitialized());
+    // Shutting down again is a no-op.
+    perfetto::Tracing::Shutdown();
+    PERFETTO_CHECK(!perfetto::Tracing::IsInitialized());
+  }
+
   template <typename DataSourceType>
   TestDataSourceHandle* RegisterDataSource(std::string name) {
     perfetto::DataSourceDescriptor dsd;
diff --git a/src/tracing/tracing.cc b/src/tracing/tracing.cc
index adaffad..f23136f 100644
--- a/src/tracing/tracing.cc
+++ b/src/tracing/tracing.cc
@@ -68,6 +68,15 @@
 }
 
 // static
+void Tracing::Shutdown() {
+  std::unique_lock<std::mutex> lock(InitializedMutex());
+  if (!g_was_initialized)
+    return;
+  internal::TracingMuxerImpl::Shutdown();
+  g_was_initialized = false;
+}
+
+// static
 void Tracing::ResetForTesting() {
   std::unique_lock<std::mutex> lock(InitializedMutex());
   if (!g_was_initialized)