filesystem: Migrate from probes_producer and add mount points

Bug: 73625480
Change-Id: I83146cfa6589af0bcf3301397e6f79b02f405fdc
diff --git a/src/traced/probes/filesystem/inode_file_data_source.cc b/src/traced/probes/filesystem/inode_file_data_source.cc
new file mode 100644
index 0000000..b1a6aaa
--- /dev/null
+++ b/src/traced/probes/filesystem/inode_file_data_source.cc
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/traced/probes/filesystem/inode_file_data_source.h"
+
+#include <dirent.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <queue>
+
+#include "include/perfetto/ftrace_reader/ftrace_controller.h"
+#include "perfetto/base/logging.h"
+#include "perfetto/tracing/core/trace_packet.h"
+
+#include "perfetto/trace/trace_packet.pbzero.h"
+
+namespace perfetto {
+
+using BlockDeviceID = decltype(stat::st_dev);
+
+void CreateDeviceToInodeMap(
+    const std::string& root_directory,
+    std::map<BlockDeviceID, std::map<Inode, InodeMapValue>>* block_device_map) {
+  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;
+      Inode inode_number = entry->d_ino;
+      struct stat buf;
+      if (lstat(filepath.c_str(), &buf) != 0)
+        continue;
+      BlockDeviceID block_device_id = buf.st_dev;
+      std::map<Inode, InodeMapValue>& inode_map =
+          (*block_device_map)[block_device_id];
+      // Default
+      protos::pbzero::InodeFileMap_Entry_Type type =
+          protos::pbzero::InodeFileMap_Entry_Type_UNKNOWN;
+      // Readdir and stat not guaranteed to have directory info for all systems
+      if (entry->d_type == DT_DIR || S_ISDIR(buf.st_mode)) {
+        // 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 || S_ISREG(buf.st_mode)) {
+        type = protos::pbzero::InodeFileMap_Entry_Type_FILE;
+      }
+      inode_map[inode_number].SetType(type);
+      inode_map[inode_number].AddPath(filepath + filename);
+    }
+    closedir(dir);
+  }
+}
+
+InodeFileDataSource::InodeFileDataSource(
+    std::map<BlockDeviceID, std::map<Inode, InodeMapValue>>* file_system_inodes,
+    std::unique_ptr<TraceWriter> writer)
+    : file_system_inodes_(file_system_inodes), writer_(std::move(writer)) {}
+
+void InodeFileDataSource::WriteInodes(const FtraceMetadata& metadata) {
+  PERFETTO_DLOG("Write Inodes start");
+
+  if (mount_points_.empty()) {
+    mount_points_ = ParseMounts();
+  }
+  // Group inodes from FtraceMetadata by block device
+  auto inodes = metadata.inodes;
+  std::map<BlockDeviceID, std::set<Inode>> inode_file_maps;
+  for (const auto& inode : inodes) {
+    BlockDeviceID block_device_id = inode.first;
+    Inode inode_number = inode.second;
+    inode_file_maps[block_device_id].emplace(inode_number);
+  }
+  // Write a TracePacket with an InodeFileMap proto for each block device id
+  for (const auto& inode_file_map_data : inode_file_maps) {
+    auto trace_packet = writer_->NewTracePacket();
+    auto inode_file_map = trace_packet->set_inode_file_map();
+    // Add block device id
+    BlockDeviceID block_device_id = inode_file_map_data.first;
+    inode_file_map->set_block_device_id(block_device_id);
+    // Add mount points
+    auto range = mount_points_.equal_range(block_device_id);
+    for (std::multimap<BlockDeviceID, std::string>::iterator it = range.first;
+         it != range.second; ++it) {
+      inode_file_map->add_mount_points(it->second.c_str());
+    }
+    // Add entries for each inode number
+    std::set<Inode> inode_numbers = inode_file_map_data.second;
+    for (const auto& inode_number : inode_numbers) {
+      auto* entry = inode_file_map->add_entries();
+      entry->set_inode_number(inode_number);
+      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_number);
+        if (inode_map != block_device_map->second.end()) {
+          entry->set_type(inode_map->second.type());
+          for (const auto& path : inode_map->second.paths())
+            entry->add_paths(path.c_str());
+        }
+      }
+    }
+    trace_packet->Finalize();
+  }
+}
+
+}  // namespace perfetto