filesystem: Migrate from probes_producer and add mount points
Bug: 73625480
Change-Id: I83146cfa6589af0bcf3301397e6f79b02f405fdc
diff --git a/Android.bp b/Android.bp
index 6c25b26..64d6a50 100644
--- a/Android.bp
+++ b/Android.bp
@@ -59,6 +59,9 @@
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
"src/protozero/scattered_stream_writer.cc",
+ "src/traced/probes/filesystem/fs_mount.cc",
+ "src/traced/probes/filesystem/inode_file_data_source.cc",
+ "src/traced/probes/filesystem/lru_inode_cache.cc",
"src/traced/probes/probes.cc",
"src/traced/probes/probes_producer.cc",
"src/traced/probes/process_stats_data_source.cc",
@@ -276,6 +279,9 @@
"src/protozero/message_handle.cc",
"src/protozero/proto_utils.cc",
"src/protozero/scattered_stream_writer.cc",
+ "src/traced/probes/filesystem/fs_mount.cc",
+ "src/traced/probes/filesystem/inode_file_data_source.cc",
+ "src/traced/probes/filesystem/lru_inode_cache.cc",
"src/traced/probes/probes_producer.cc",
"src/traced/probes/process_stats_data_source.cc",
"src/tracing/core/chrome_config.cc",
@@ -3124,6 +3130,7 @@
"src/protozero/test/protozero_conformance_unittest.cc",
"src/traced/probes/filesystem/fs_mount.cc",
"src/traced/probes/filesystem/fs_mount_unittest.cc",
+ "src/traced/probes/filesystem/inode_file_data_source.cc",
"src/traced/probes/filesystem/lru_inode_cache.cc",
"src/traced/probes/filesystem/lru_inode_cache_unittest.cc",
"src/traced/probes/probes_producer.cc",
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 51eb46d..26e1965 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -34,6 +34,7 @@
"../../base",
"../../process_stats:process_stats",
"../../tracing:tracing",
+ "filesystem",
]
sources = [
"probes_producer.cc",
diff --git a/src/traced/probes/filesystem/BUILD.gn b/src/traced/probes/filesystem/BUILD.gn
index 40aebc7..32a0361 100644
--- a/src/traced/probes/filesystem/BUILD.gn
+++ b/src/traced/probes/filesystem/BUILD.gn
@@ -13,12 +13,19 @@
# limitations under the License.
source_set("filesystem") {
+ public_deps = [
+ "../../../../protos/perfetto/trace/filesystem:zero",
+ ]
deps = [
"../../../../gn:default_deps",
+ "../../../base",
+ "../../../ftrace_reader",
]
sources = [
"fs_mount.cc",
"fs_mount.h",
+ "inode_file_data_source.cc",
+ "inode_file_data_source.h",
"lru_inode_cache.cc",
"lru_inode_cache.h",
]
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
diff --git a/src/traced/probes/filesystem/inode_file_data_source.h b/src/traced/probes/filesystem/inode_file_data_source.h
new file mode 100644
index 0000000..faa02f2
--- /dev/null
+++ b/src/traced/probes/filesystem/inode_file_data_source.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef SRC_TRACED_PROBES_FILESYSTEM_INODE_FILE_DATA_SOURCE_H_
+#define SRC_TRACED_PROBES_FILESYSTEM_INODE_FILE_DATA_SOURCE_H_
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <map>
+#include <set>
+#include <string>
+
+#include "perfetto/ftrace_reader/ftrace_controller.h"
+#include "perfetto/tracing/core/basic_types.h"
+#include "perfetto/tracing/core/trace_writer.h"
+#include "src/traced/probes/filesystem/fs_mount.h"
+
+#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
+
+namespace perfetto {
+
+using Inode = uint64_t;
+using InodeFileMap = protos::pbzero::InodeFileMap;
+
+class InodeMapValue {
+ public:
+ protos::pbzero::InodeFileMap_Entry_Type type() const { return entry_type_; }
+ std::set<std::string> paths() const { return paths_; }
+ void SetType(protos::pbzero::InodeFileMap_Entry_Type entry_type) {
+ entry_type_ = entry_type;
+ }
+ void SetPaths(std::set<std::string> paths) { paths_ = paths; }
+ void AddPath(std::string path) { paths_.emplace(path); }
+
+ private:
+ protos::pbzero::InodeFileMap_Entry_Type entry_type_;
+ std::set<std::string> paths_;
+};
+
+void CreateDeviceToInodeMap(
+ const std::string& root_directory,
+ std::map<BlockDeviceID, std::map<Inode, InodeMapValue>>* block_device_map);
+
+class InodeFileDataSource {
+ public:
+ explicit InodeFileDataSource(
+ std::map<BlockDeviceID, std::map<Inode, InodeMapValue>>*
+ file_system_inodes,
+ std::unique_ptr<TraceWriter> writer);
+
+ void WriteInodes(const FtraceMetadata& metadata);
+
+ private:
+ std::map<BlockDeviceID, std::map<Inode, InodeMapValue>>* file_system_inodes_;
+ std::multimap<BlockDeviceID, std::string> mount_points_;
+ std::unique_ptr<TraceWriter> writer_;
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACED_PROBES_FILESYSTEM_INODE_FILE_DATA_SOURCE_H_
diff --git a/src/traced/probes/filesystem/inode_file_data_source_unittest.cc b/src/traced/probes/filesystem/inode_file_data_source_unittest.cc
new file mode 100644
index 0000000..63d9fe8
--- /dev/null
+++ b/src/traced/probes/filesystem/inode_file_data_source_unittest.cc
@@ -0,0 +1,28 @@
+/*
+ * 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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace perfetto {
+namespace {
+
+// TODO(azappone): Add tests
+
+} // namespace
+} // namespace perfetto
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 0c1025d..27064fd 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -28,6 +28,7 @@
#include "perfetto/tracing/core/ftrace_config.h"
#include "perfetto/tracing/core/trace_config.h"
#include "perfetto/tracing/core/trace_packet.h"
+#include "src/traced/probes/filesystem/inode_file_data_source.h"
#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
@@ -93,7 +94,7 @@
if (source_config.name() == kFtraceSourceName) {
CreateFtraceDataSourceInstance(id, source_config);
} else if (source_config.name() == kInodeFileMapSourceName) {
- CreateInodeFileMapDataSourceInstance(id, source_config);
+ CreateInodeFileDataSourceInstance(id, source_config);
} else if (source_config.name() == kProcessStatsSourceName) {
CreateProcessStatsDataSourceInstance(id, source_config);
} else {
@@ -152,16 +153,17 @@
AddWatchdogsTimer(id, source_config);
}
-void ProbesProducer::CreateInodeFileMapDataSourceInstance(
+void ProbesProducer::CreateInodeFileDataSourceInstance(
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()));
- CreateDeviceToInodeMap("/system/", &system_inodes_);
- auto file_map_source = std::unique_ptr<InodeFileMapDataSource>(
- new InodeFileMapDataSource(&system_inodes_, std::move(trace_writer)));
+ if (system_inodes_.empty())
+ CreateDeviceToInodeMap("/system/", &system_inodes_);
+ auto file_map_source = std::unique_ptr<InodeFileDataSource>(
+ new InodeFileDataSource(&system_inodes_, std::move(trace_writer)));
file_map_sources_.emplace(id, std::move(file_map_source));
AddWatchdogsTimer(id, source_config);
}
@@ -179,50 +181,6 @@
it_and_inserted.first->second->WriteAllProcesses();
}
-// static
-void ProbesProducer::CreateDeviceToInodeMap(
- const std::string& root_directory,
- std::map<uint32_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;
- struct stat buf;
- if (lstat(filepath.c_str(), &buf) != 0)
- continue;
- uint32_t block_device_id = buf.st_dev;
- InodeMap& inode_map = (*block_device_map)[block_device_id];
- // Default
- 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].first = type;
- inode_map[inode_number].second.emplace(filepath + filename);
- }
- closedir(dir);
- }
-}
-
void ProbesProducer::TearDownDataSourceInstance(DataSourceInstanceID id) {
PERFETTO_LOG("Producer stop (id=%" PRIu64 ")", id);
// |id| could be the id of any of the datasources we handle:
@@ -292,39 +250,8 @@
}
void ProbesProducer::SinkDelegate::OnInodes(
- const std::vector<std::pair<uint64_t, uint32_t>>& inodes) {
- PERFETTO_DLOG("Saw FtraceBundle with %zu inodes.", inodes.size());
-}
-
-ProbesProducer::InodeFileMapDataSource::InodeFileMapDataSource(
- std::map<uint32_t, InodeMap>* file_system_inodes,
- std::unique_ptr<TraceWriter> writer)
- : file_system_inodes_(file_system_inodes), 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): Get mount_points & add to the proto
- auto inodes = metadata.inodes;
- for (const auto& inode : inodes) {
- uint32_t block_device_id = inode.first;
- uint64_t inode_number = inode.second;
- 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.first);
- for (const auto& path : inode_map->second.second)
- entry->add_paths(path.c_str());
- }
- }
- }
- trace_packet->Finalize();
+ const std::vector<std::pair<Inode, uint32_t>>& inodes) {
+ PERFETTO_LOG("Saw FtraceBundle with %zu inodes.", inodes.size());
}
} // namespace perfetto
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index e323e9d..5a4d7e3 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -26,6 +26,7 @@
#include "perfetto/tracing/core/producer.h"
#include "perfetto/tracing/core/trace_writer.h"
#include "perfetto/tracing/ipc/producer_ipc_client.h"
+#include "src/traced/probes/filesystem/inode_file_data_source.h"
#include "src/traced/probes/process_stats_data_source.h"
#include "perfetto/trace/filesystem/inode_file_map.pbzero.h"
@@ -52,19 +53,14 @@
void CreateProcessStatsDataSourceInstance(
DataSourceInstanceID id,
const DataSourceConfig& source_config);
- void CreateInodeFileMapDataSourceInstance(
- DataSourceInstanceID id,
- const DataSourceConfig& source_config);
+ void CreateInodeFileDataSourceInstance(DataSourceInstanceID id,
+ const DataSourceConfig& source_config);
void OnMetadata(const FtraceMetadata& metadata);
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:
@@ -79,7 +75,7 @@
const FtraceMetadata& metadata) override;
void set_sink(std::unique_ptr<FtraceSink> sink) { sink_ = std::move(sink); }
- void OnInodes(const std::vector<std::pair<uint64_t, uint32_t>>& inodes);
+ void OnInodes(const std::vector<std::pair<Inode, uint32_t>>& inodes);
private:
base::TaskRunner* task_runner_;
@@ -93,20 +89,6 @@
base::WeakPtrFactory<SinkDelegate> weak_factory_;
};
- class InodeFileMapDataSource {
- public:
- explicit InodeFileMapDataSource(
- std::map<uint32_t, InodeMap>* file_system_inodes,
- std::unique_ptr<TraceWriter> writer);
- ~InodeFileMapDataSource();
-
- void WriteInodes(const FtraceMetadata& metadata);
-
- private:
- std::map<uint32_t, InodeMap>* file_system_inodes_;
- std::unique_ptr<TraceWriter> writer_;
- };
-
enum State {
kNotStarted = 0,
kNotConnected,
@@ -122,9 +104,6 @@
void IncreaseConnectionBackoff();
void AddWatchdogsTimer(DataSourceInstanceID id,
const DataSourceConfig& source_config);
- static void CreateDeviceToInodeMap(
- const std::string& root_directory,
- std::map<uint32_t, InodeMap>* block_device_map);
State state_ = kNotStarted;
base::TaskRunner* task_runner_;
@@ -137,9 +116,9 @@
process_stats_sources_;
std::map<DataSourceInstanceID, std::unique_ptr<SinkDelegate>> delegates_;
std::map<DataSourceInstanceID, base::Watchdog::Timer> watchdogs_;
- std::map<DataSourceInstanceID, std::unique_ptr<InodeFileMapDataSource>>
+ std::map<DataSourceInstanceID, std::unique_ptr<InodeFileDataSource>>
file_map_sources_;
- std::map<uint32_t, InodeMap> system_inodes_;
+ std::map<BlockDeviceID, std::map<Inode, InodeMapValue>> system_inodes_;
};
} // namespace perfetto