perfetto: set memory and CPU guardrails on traced and traced_probes

Bug: 73051936
Bug: 73052380
Change-Id: I0db375ea5b7ac4e26b52d74e860d96cdf7fbbd5d
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index 6281744..78ccea6 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -40,6 +40,13 @@
     }
   }
 
+  // Set the watchdog to kill the process if we average more than 32MB of
+  // memory or 75% CPU over a 30 second window.
+  base::Watchdog* watchdog = base::Watchdog::GetInstance();
+  watchdog->SetCpuLimit(75, 30 * 1000);
+  watchdog->SetMemoryLimit(32 * 1024 * 1024, 30 * 1000);
+  watchdog->Start();
+
   PERFETTO_LOG("Starting %s service", argv[0]);
   base::UnixTaskRunner task_runner;
   ProbesProducer producer;
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 8107312..b3f7812 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -15,6 +15,7 @@
  */
 
 #include "perfetto/base/unix_task_runner.h"
+#include "perfetto/base/watchdog.h"
 #include "perfetto/traced/traced.h"
 #include "perfetto/tracing/ipc/service_ipc_host.h"
 
@@ -41,6 +42,13 @@
     svc->Start(PERFETTO_PRODUCER_SOCK_NAME, PERFETTO_CONSUMER_SOCK_NAME);
   }
 
+  // Set the CPU limit and start the watchdog running. The memory limit will
+  // be set inside the service code as it relies on the size of buffers.
+  // The CPU limit is 75% over a 30 second interval.
+  base::Watchdog* watchdog = base::Watchdog::GetInstance();
+  watchdog->SetCpuLimit(75, 30 * 1000);
+  watchdog->Start();
+
   PERFETTO_ILOG("Started traced, listening on %s %s",
                 PERFETTO_PRODUCER_SOCK_NAME, PERFETTO_CONSUMER_SOCK_NAME);
   task_runner.Run();
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index 5f30a87..7da32f7 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -105,6 +105,8 @@
   auto it_and_inserted = producers_.emplace(id, endpoint.get());
   PERFETTO_DCHECK(it_and_inserted.second);
   task_runner_->PostTask(std::bind(&Producer::OnConnect, endpoint->producer_));
+
+  UpdateMemoryGuardrail();
   return std::move(endpoint);
 }
 
@@ -122,6 +124,7 @@
   }
 
   producers_.erase(id);
+  UpdateMemoryGuardrail();
 }
 
 ServiceImpl::ProducerEndpointImpl* ServiceImpl::GetProducer(
@@ -238,6 +241,7 @@
       break;
     }
   }
+  UpdateMemoryGuardrail();
 
   // This can happen if either:
   // - All the kMaxTraceBufferID slots are taken.
@@ -433,6 +437,8 @@
     buffers_.erase(buffer_id);
   }
   tracing_sessions_.erase(tsid);
+  UpdateMemoryGuardrail();
+
   PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid,
                tracing_sessions_.size());
 }
@@ -595,6 +601,27 @@
   return last_producer_id_;
 }
 
+void ServiceImpl::UpdateMemoryGuardrail() {
+#if !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+  uint64_t total_buffer_bytes = 0;
+
+  // Sum up all the shared memory buffers.
+  for (const auto& id_to_producer : producers_) {
+    total_buffer_bytes += id_to_producer.second->shared_memory()->size();
+  }
+
+  // Sum up all the trace buffers.
+  for (const auto& id_to_buffer : buffers_) {
+    total_buffer_bytes += id_to_buffer.second.size;
+  }
+
+  // Set the guard rail to 32MB + the sum of all the buffers over a 30 second
+  // interval.
+  uint64_t guardrail = 32 * 1024 * 1024 + total_buffer_bytes;
+  base::Watchdog::GetInstance()->SetMemoryLimit(guardrail, 30 * 1000);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ServiceImpl::ConsumerEndpointImpl implementation
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tracing/core/service_impl.h b/src/tracing/core/service_impl.h
index 7725c12..2717d2d 100644
--- a/src/tracing/core/service_impl.h
+++ b/src/tracing/core/service_impl.h
@@ -238,6 +238,10 @@
   // session doesn't exists.
   TracingSession* GetTracingSession(TracingSessionID);
 
+  // Update the memory guard rail by using the latest information from the
+  // shared memory and trace buffers.
+  void UpdateMemoryGuardrail();
+
   base::TaskRunner* const task_runner_;
   std::unique_ptr<SharedMemory::Factory> shm_factory_;
   ProducerID last_producer_id_ = 0;