Merge "perfetto: enable traced on CTS running devices"
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 718e51f..77d1c02 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -163,8 +163,9 @@
                id, source_config.target_buffer());
   auto trace_writer = endpoint_->CreateTraceWriter(
       static_cast<BufferID>(source_config.target_buffer()));
+  CreateDeviceToInodeMap("/system/", &system_inodes_);
   auto file_map_source = std::unique_ptr<InodeFileMapDataSource>(
-      new InodeFileMapDataSource(std::move(trace_writer)));
+      new InodeFileMapDataSource(&system_inodes_, std::move(trace_writer)));
   file_map_sources_.emplace(id, std::move(file_map_source));
   AddWatchdogsTimer(id, source_config);
 }
@@ -200,6 +201,46 @@
   trace_packet->Finalize();
 }
 
+// static
+void ProbesProducer::CreateDeviceToInodeMap(
+    const std::string& root_directory,
+    std::map<uint64_t, InodeMap>* block_device_map) {
+  // Return immediately if we've already filled in the system map
+  if (!block_device_map->empty())
+    return;
+  std::queue<std::string> queue;
+  queue.push(root_directory);
+  while (!queue.empty()) {
+    struct dirent* entry;
+    std::string filepath = queue.front();
+    queue.pop();
+    DIR* dir = opendir(filepath.c_str());
+    filepath += "/";
+    if (dir == nullptr)
+      continue;
+    while ((entry = readdir(dir)) != nullptr) {
+      std::string filename = entry->d_name;
+      if (filename == "." || filename == "..")
+        continue;
+      uint64_t inode_number = entry->d_ino;
+      uint64_t block_device_id = 0;
+      InodeMap& inode_map = (*block_device_map)[block_device_id];
+      // Default
+      Type type = protos::pbzero::InodeFileMap_Entry_Type_UNKNOWN;
+      if (entry->d_type == DT_DIR) {
+        // Continue iterating through files if current entry is a directory
+        queue.push(filepath + filename);
+        type = protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY;
+      } else if (entry->d_type == DT_REG) {
+        type = protos::pbzero::InodeFileMap_Entry_Type_FILE;
+      }
+      inode_map[inode_number].first = type;
+      inode_map[inode_number].second.emplace(filepath + filename);
+    }
+    closedir(dir);
+  }
+}
+
 void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
   PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
   PERFETTO_DCHECK(instances_.count(id));
@@ -278,8 +319,9 @@
 }
 
 ProbesProducer::InodeFileMapDataSource::InodeFileMapDataSource(
+    std::map<uint64_t, InodeMap>* file_system_inodes,
     std::unique_ptr<TraceWriter> writer)
-    : writer_(std::move(writer)) {}
+    : file_system_inodes_(file_system_inodes), writer_(std::move(writer)) {}
 
 ProbesProducer::InodeFileMapDataSource::~InodeFileMapDataSource() = default;
 
@@ -287,12 +329,21 @@
     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
+  // TODO(azappone): Get block_device_id and mount_points & add to the proto
+  uint64_t block_device_id = 0;
   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
+    auto block_device_map = file_system_inodes_->find(block_device_id);
+    if (block_device_map != file_system_inodes_->end()) {
+      auto inode_map = block_device_map->second.find(inode);
+      if (inode_map != block_device_map->second.end()) {
+        entry->set_type(inode_map->second.first);
+        for (const auto& path : inode_map->second.second)
+          entry->add_paths(path.c_str());
+      }
+    }
   }
   trace_packet->Finalize();
 }
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index bc1b91d..457975b 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -59,6 +59,10 @@
  private:
   using FtraceBundleHandle =
       protozero::MessageHandle<protos::pbzero::FtraceEventBundle>;
+  using Type = protos::pbzero::InodeFileMap_Entry_Type;
+  using InodeMap = std::map<uint64_t,
+                            std::pair<protos::pbzero::InodeFileMap_Entry_Type,
+                                      std::set<std::string>>>;
 
   class SinkDelegate : public FtraceSink::Delegate {
    public:
@@ -89,12 +93,15 @@
 
   class InodeFileMapDataSource {
    public:
-    explicit InodeFileMapDataSource(std::unique_ptr<TraceWriter> writer);
+    explicit InodeFileMapDataSource(
+        std::map<uint64_t, InodeMap>* file_system_inodes,
+        std::unique_ptr<TraceWriter> writer);
     ~InodeFileMapDataSource();
 
     void WriteInodes(const FtraceMetadata& metadata);
 
    private:
+    std::map<uint64_t, InodeMap>* file_system_inodes_;
     std::unique_ptr<TraceWriter> writer_;
   };
 
@@ -110,6 +117,9 @@
   void IncreaseConnectionBackoff();
   void AddWatchdogsTimer(DataSourceInstanceID id,
                          const DataSourceConfig& source_config);
+  static void CreateDeviceToInodeMap(
+      const std::string& root_directory,
+      std::map<uint64_t, InodeMap>* block_device_map);
 
   State state_ = kNotStarted;
   base::TaskRunner* task_runner_;
@@ -124,6 +134,7 @@
   std::map<DataSourceInstanceID, base::Watchdog::Timer> watchdogs_;
   std::map<DataSourceInstanceID, std::unique_ptr<InodeFileMapDataSource>>
       file_map_sources_;
+  std::map<uint64_t, InodeMap> system_inodes_;
 };
 }  // namespace perfetto