| // Copyright 2021 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/metrics/structured/external_metrics.h" |
| |
| #include <sys/file.h> |
| |
| #include "base/containers/fixed_flat_set.h" |
| #include "base/files/file.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/task/task_runner_util.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "base/threading/scoped_blocking_call.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "components/metrics/structured/storage.pb.h" |
| #include "components/metrics/structured/structured_metrics_features.h" |
| |
| namespace metrics { |
| namespace structured { |
| namespace { |
| |
| // TODO(b/181724341): Remove this once the bluetooth metrics are fully enabled. |
| void MaybeFilterBluetoothEvents( |
| google::protobuf::RepeatedPtrField<metrics::StructuredEventProto>* events) { |
| // Event name hashes of all bluetooth events listed in |
| // src/platform2/metrics/structured/structured.xml. |
| static constexpr auto kBluetoothEventHashes = base::MakeFixedFlatSet<uint64_t>({ |
| // BluetoothAdapterStateChanged |
| UINT64_C(959829856916771459), |
| // BluetoothPairingStateChanged |
| UINT64_C(11839023048095184048), |
| // BluetoothAclConnectionStateChanged |
| UINT64_C(1880220404408566268), |
| // BluetoothProfileConnectionStateChanged |
| UINT64_C(7217682640379679663), |
| // BluetoothDeviceInfoReport |
| UINT64_C(1506471670382892394) |
| }); |
| |
| if (base::FeatureList::IsEnabled(kBluetoothSessionizedMetrics)) |
| return; |
| |
| // Remove all bluetooth events. |
| auto it = events->begin(); |
| while (it != events->end()) { |
| if (kBluetoothEventHashes.contains(it->event_name_hash())) { |
| it = events->erase(it); |
| } else { |
| ++it; |
| } |
| } |
| } |
| |
| EventsProto ReadAndDeleteEvents(const base::FilePath& directory) { |
| base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, |
| base::BlockingType::MAY_BLOCK); |
| EventsProto result; |
| if (!base::DirectoryExists(directory)) |
| return result; |
| |
| base::FileEnumerator enumerator(directory, false, |
| base::FileEnumerator::FILES); |
| for (base::FilePath path = enumerator.Next(); !path.empty(); |
| path = enumerator.Next()) { |
| std::string proto_str; |
| EventsProto proto; |
| |
| bool read_ok = base::ReadFileToString(path, &proto_str) && |
| proto.ParseFromString(proto_str); |
| base::DeleteFile(path); |
| |
| if (!read_ok) |
| continue; |
| |
| // MergeFrom performs a copy that could be a move if done manually. But all |
| // the protos here are expected to be small, so let's keep it simple. |
| result.mutable_uma_events()->MergeFrom(proto.uma_events()); |
| result.mutable_non_uma_events()->MergeFrom(proto.non_uma_events()); |
| } |
| |
| MaybeFilterBluetoothEvents(result.mutable_uma_events()); |
| MaybeFilterBluetoothEvents(result.mutable_non_uma_events()); |
| return result; |
| } |
| |
| } // namespace |
| |
| ExternalMetrics::ExternalMetrics(const base::FilePath& events_directory, |
| const base::TimeDelta& collection_interval, |
| MetricsCollectedCallback callback) |
| : events_directory_(events_directory), |
| collection_interval_(collection_interval), |
| callback_(std::move(callback)), |
| task_runner_(base::ThreadPool::CreateSequencedTaskRunner( |
| {base::TaskPriority::BEST_EFFORT, base::MayBlock(), |
| base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) { |
| ScheduleCollector(); |
| } |
| |
| ExternalMetrics::~ExternalMetrics() = default; |
| |
| void ExternalMetrics::CollectEventsAndReschedule() { |
| CollectEvents(); |
| ScheduleCollector(); |
| } |
| |
| void ExternalMetrics::ScheduleCollector() { |
| base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&ExternalMetrics::CollectEventsAndReschedule, |
| weak_factory_.GetWeakPtr()), |
| collection_interval_); |
| } |
| |
| void ExternalMetrics::CollectEvents() { |
| task_runner_->PostTaskAndReplyWithResult( |
| FROM_HERE, base::BindOnce(&ReadAndDeleteEvents, events_directory_), |
| base::BindOnce(callback_)); |
| } |
| |
| } // namespace structured |
| } // namespace metrics |