probes_producer: Add initial code to put inodes into their own trace packet

Bug: 73625480
Change-Id: I6fa2e9b7dc4d378a0f57bf049af7a8c6d7833a82
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 7a36f32..718e51f 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -17,6 +17,7 @@
 #include "src/traced/probes/probes_producer.h"
 
 #include <stdio.h>
+#include <queue>
 #include <string>
 
 #include "perfetto/base/logging.h"
@@ -30,6 +31,7 @@
 #include "src/process_stats/file_utils.h"
 #include "src/process_stats/procfs_utils.h"
 
+#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
 #include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
 #include "perfetto/trace/ps/process_tree.pbzero.h"
 #include "perfetto/trace/trace_packet.pbzero.h"
@@ -41,6 +43,7 @@
 uint64_t kMaxConnectionBackoffMs = 30 * 1000;
 const char* kFtraceSourceName = "com.google.perfetto.ftrace";
 const char* kProcessStatsSourceName = "com.google.perfetto.process_stats";
+const char* kInodeFileMapSourceName = "com.google.perfetto.inode_file_map";
 
 }  // namespace.
 
@@ -69,6 +72,11 @@
   process_stats_descriptor.set_name(kProcessStatsSourceName);
   endpoint_->RegisterDataSource(process_stats_descriptor,
                                 [](DataSourceInstanceID) {});
+
+  DataSourceDescriptor inode_map_descriptor;
+  inode_map_descriptor.set_name(kInodeFileMapSourceName);
+  endpoint_->RegisterDataSource(inode_map_descriptor,
+                                [](DataSourceInstanceID) {});
 }
 
 void ProbesProducer::OnDisconnect() {
@@ -90,12 +98,21 @@
     CreateFtraceDataSourceInstance(id, source_config);
   } else if (source_config.name() == kProcessStatsSourceName) {
     CreateProcessStatsDataSourceInstance(source_config);
+  } else if (source_config.name() == kInodeFileMapSourceName) {
+    CreateInodeFileMapDataSourceInstance(id, source_config);
   } else {
     PERFETTO_ELOG("Data source name: %s not recognised.",
                   source_config.name().c_str());
   }
 }
 
+void ProbesProducer::AddWatchdogsTimer(DataSourceInstanceID id,
+                                       const DataSourceConfig& source_config) {
+  if (source_config.trace_duration_ms() != 0)
+    watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
+                               5000 + 2 * source_config.trace_duration_ms()));
+}
+
 void ProbesProducer::CreateFtraceDataSourceInstance(
     DataSourceInstanceID id,
     const DataSourceConfig& source_config) {
@@ -136,9 +153,20 @@
   }
   delegate->sink(std::move(sink));
   delegates_.emplace(id, std::move(delegate));
-  if (source_config.trace_duration_ms() != 0)
-    watchdogs_.emplace(id, base::Watchdog::GetInstance()->CreateFatalTimer(
-                               5000 + 2 * source_config.trace_duration_ms()));
+  AddWatchdogsTimer(id, source_config);
+}
+
+void ProbesProducer::CreateInodeFileMapDataSourceInstance(
+    DataSourceInstanceID id,
+    const DataSourceConfig& source_config) {
+  PERFETTO_LOG("Inode file map start (id=%" PRIu64 ", target_buf=%" PRIu32 ")",
+               id, source_config.target_buffer());
+  auto trace_writer = endpoint_->CreateTraceWriter(
+      static_cast<BufferID>(source_config.target_buffer()));
+  auto file_map_source = std::unique_ptr<InodeFileMapDataSource>(
+      new InodeFileMapDataSource(std::move(trace_writer)));
+  file_map_sources_.emplace(id, std::move(file_map_source));
+  AddWatchdogsTimer(id, source_config);
 }
 
 void ProbesProducer::CreateProcessStatsDataSourceInstance(
@@ -180,6 +208,10 @@
     PERFETTO_DCHECK(removed == 1);
     // Might return 0 if trace_duration_ms == 0.
     watchdogs_.erase(id);
+  } else if (instances_[id] == kInodeFileMapSourceName) {
+    size_t removed = file_map_sources_.erase(id);
+    PERFETTO_DCHECK(removed == 1);
+    watchdogs_.erase(id);
   }
 }
 
@@ -233,7 +265,6 @@
   if (!metadata.inodes.empty()) {
     auto weak_this = weak_factory_.GetWeakPtr();
     auto inodes = metadata.inodes;
-    // TODO(hjd): This call back should be one in total, not one per CPU.
     task_runner_->PostTask([weak_this, inodes] {
       if (weak_this)
         weak_this->OnInodes(inodes);
@@ -246,4 +277,24 @@
   PERFETTO_DLOG("Saw FtraceBundle with %zu inodes.", inodes.size());
 }
 
+ProbesProducer::InodeFileMapDataSource::InodeFileMapDataSource(
+    std::unique_ptr<TraceWriter> writer)
+    : writer_(std::move(writer)) {}
+
+ProbesProducer::InodeFileMapDataSource::~InodeFileMapDataSource() = default;
+
+void ProbesProducer::InodeFileMapDataSource::WriteInodes(
+    const FtraceMetadata& metadata) {
+  auto trace_packet = writer_->NewTracePacket();
+  auto inode_file_map = trace_packet->set_inode_file_map();
+  // TODO(azappone): Add block_device_id and mount_points
+  auto inodes = metadata.inodes;
+  for (const auto& inode : inodes) {
+    auto* entry = inode_file_map->add_entries();
+    entry->set_inode_number(inode);
+    // TODO(azappone): Add resolving filepaths and type
+  }
+  trace_packet->Finalize();
+}
+
 }  // namespace perfetto