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