1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "components/metrics/structured/external_metrics.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <string_view>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include "base/containers/fixed_flat_set.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/files/dir_reader_posix.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/files/file.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/task/sequenced_task_runner.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/task/task_traits.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
20*6777b538SAndroid Build Coastguard Worker #include "components/metrics/structured/histogram_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "components/metrics/structured/proto/event_storage.pb.h"
22*6777b538SAndroid Build Coastguard Worker #include "components/metrics/structured/structured_metrics_features.h"
23*6777b538SAndroid Build Coastguard Worker
24*6777b538SAndroid Build Coastguard Worker namespace metrics::structured {
25*6777b538SAndroid Build Coastguard Worker namespace {
26*6777b538SAndroid Build Coastguard Worker
FilterEvents(google::protobuf::RepeatedPtrField<metrics::StructuredEventProto> * events,const base::flat_set<uint64_t> & disallowed_projects)27*6777b538SAndroid Build Coastguard Worker void FilterEvents(
28*6777b538SAndroid Build Coastguard Worker google::protobuf::RepeatedPtrField<metrics::StructuredEventProto>* events,
29*6777b538SAndroid Build Coastguard Worker const base::flat_set<uint64_t>& disallowed_projects) {
30*6777b538SAndroid Build Coastguard Worker auto it = events->begin();
31*6777b538SAndroid Build Coastguard Worker while (it != events->end()) {
32*6777b538SAndroid Build Coastguard Worker if (disallowed_projects.contains(it->project_name_hash())) {
33*6777b538SAndroid Build Coastguard Worker it = events->erase(it);
34*6777b538SAndroid Build Coastguard Worker } else {
35*6777b538SAndroid Build Coastguard Worker ++it;
36*6777b538SAndroid Build Coastguard Worker }
37*6777b538SAndroid Build Coastguard Worker }
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker
Platform2ProjectName(uint64_t project_name_hash)40*6777b538SAndroid Build Coastguard Worker std::string_view Platform2ProjectName(uint64_t project_name_hash) {
41*6777b538SAndroid Build Coastguard Worker switch (project_name_hash) {
42*6777b538SAndroid Build Coastguard Worker case UINT64_C(827233605053062635):
43*6777b538SAndroid Build Coastguard Worker return "AudioPeripheral";
44*6777b538SAndroid Build Coastguard Worker case UINT64_C(524369188505453537):
45*6777b538SAndroid Build Coastguard Worker return "AudioPeripheralInfo";
46*6777b538SAndroid Build Coastguard Worker case UINT64_C(9074739597929991885):
47*6777b538SAndroid Build Coastguard Worker return "Bluetooth";
48*6777b538SAndroid Build Coastguard Worker case UINT64_C(1745381000935843040):
49*6777b538SAndroid Build Coastguard Worker return "BluetoothDevice";
50*6777b538SAndroid Build Coastguard Worker case UINT64_C(11181229631788078243):
51*6777b538SAndroid Build Coastguard Worker return "BluetoothChipset";
52*6777b538SAndroid Build Coastguard Worker case UINT64_C(8206859287963243715):
53*6777b538SAndroid Build Coastguard Worker return "Cellular";
54*6777b538SAndroid Build Coastguard Worker case UINT64_C(11294265225635075664):
55*6777b538SAndroid Build Coastguard Worker return "HardwareVerifier";
56*6777b538SAndroid Build Coastguard Worker case UINT64_C(4905803635010729907):
57*6777b538SAndroid Build Coastguard Worker return "RollbackEnterprise";
58*6777b538SAndroid Build Coastguard Worker case UINT64_C(9675127341789951965):
59*6777b538SAndroid Build Coastguard Worker return "Rmad";
60*6777b538SAndroid Build Coastguard Worker case UINT64_C(4690103929823698613):
61*6777b538SAndroid Build Coastguard Worker return "WiFiChipset";
62*6777b538SAndroid Build Coastguard Worker case UINT64_C(17922303533051575891):
63*6777b538SAndroid Build Coastguard Worker return "UsbDevice";
64*6777b538SAndroid Build Coastguard Worker case UINT64_C(1370722622176744014):
65*6777b538SAndroid Build Coastguard Worker return "UsbError";
66*6777b538SAndroid Build Coastguard Worker case UINT64_C(17319042894491683836):
67*6777b538SAndroid Build Coastguard Worker return "UsbPdDevice";
68*6777b538SAndroid Build Coastguard Worker case UINT64_C(6962789877417678651):
69*6777b538SAndroid Build Coastguard Worker return "UsbSession";
70*6777b538SAndroid Build Coastguard Worker case UINT64_C(4320592646346933548):
71*6777b538SAndroid Build Coastguard Worker return "WiFi";
72*6777b538SAndroid Build Coastguard Worker case UINT64_C(7302676440391025918):
73*6777b538SAndroid Build Coastguard Worker return "WiFiAP";
74*6777b538SAndroid Build Coastguard Worker default:
75*6777b538SAndroid Build Coastguard Worker return "UNKNOWN";
76*6777b538SAndroid Build Coastguard Worker }
77*6777b538SAndroid Build Coastguard Worker }
78*6777b538SAndroid Build Coastguard Worker
IncrementProjectCount(base::flat_map<uint64_t,int> & project_count_map,uint64_t project_name_hash)79*6777b538SAndroid Build Coastguard Worker void IncrementProjectCount(base::flat_map<uint64_t, int>& project_count_map,
80*6777b538SAndroid Build Coastguard Worker uint64_t project_name_hash) {
81*6777b538SAndroid Build Coastguard Worker if (project_count_map.contains(project_name_hash)) {
82*6777b538SAndroid Build Coastguard Worker project_count_map[project_name_hash] += 1;
83*6777b538SAndroid Build Coastguard Worker } else {
84*6777b538SAndroid Build Coastguard Worker project_count_map[project_name_hash] = 1;
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker
ProcessEventProtosProjectCounts(base::flat_map<uint64_t,int> & project_count_map,const EventsProto & proto)88*6777b538SAndroid Build Coastguard Worker void ProcessEventProtosProjectCounts(
89*6777b538SAndroid Build Coastguard Worker base::flat_map<uint64_t, int>& project_count_map,
90*6777b538SAndroid Build Coastguard Worker const EventsProto& proto) {
91*6777b538SAndroid Build Coastguard Worker // Process all events that were packed in the proto.
92*6777b538SAndroid Build Coastguard Worker for (const auto& event : proto.uma_events()) {
93*6777b538SAndroid Build Coastguard Worker IncrementProjectCount(project_count_map, event.project_name_hash());
94*6777b538SAndroid Build Coastguard Worker }
95*6777b538SAndroid Build Coastguard Worker
96*6777b538SAndroid Build Coastguard Worker for (const auto& event : proto.events()) {
97*6777b538SAndroid Build Coastguard Worker IncrementProjectCount(project_count_map, event.project_name_hash());
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker }
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker // TODO(b/181724341): Remove this once the bluetooth metrics are fully enabled.
MaybeFilterBluetoothEvents(google::protobuf::RepeatedPtrField<metrics::StructuredEventProto> * events)102*6777b538SAndroid Build Coastguard Worker void MaybeFilterBluetoothEvents(
103*6777b538SAndroid Build Coastguard Worker google::protobuf::RepeatedPtrField<metrics::StructuredEventProto>* events) {
104*6777b538SAndroid Build Coastguard Worker // Event name hashes of all bluetooth events listed in
105*6777b538SAndroid Build Coastguard Worker // src/platform2/metrics/structured/structured.xml.
106*6777b538SAndroid Build Coastguard Worker static constexpr auto kBluetoothEventHashes =
107*6777b538SAndroid Build Coastguard Worker base::MakeFixedFlatSet<uint64_t>(
108*6777b538SAndroid Build Coastguard Worker {// BluetoothAdapterStateChanged
109*6777b538SAndroid Build Coastguard Worker UINT64_C(959829856916771459),
110*6777b538SAndroid Build Coastguard Worker // BluetoothPairingStateChanged
111*6777b538SAndroid Build Coastguard Worker UINT64_C(11839023048095184048),
112*6777b538SAndroid Build Coastguard Worker // BluetoothAclConnectionStateChanged
113*6777b538SAndroid Build Coastguard Worker UINT64_C(1880220404408566268),
114*6777b538SAndroid Build Coastguard Worker // BluetoothProfileConnectionStateChanged
115*6777b538SAndroid Build Coastguard Worker UINT64_C(7217682640379679663),
116*6777b538SAndroid Build Coastguard Worker // BluetoothDeviceInfoReport
117*6777b538SAndroid Build Coastguard Worker UINT64_C(1506471670382892394)});
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker if (base::FeatureList::IsEnabled(kBluetoothSessionizedMetrics)) {
120*6777b538SAndroid Build Coastguard Worker return;
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker // Remove all bluetooth events.
124*6777b538SAndroid Build Coastguard Worker auto it = events->begin();
125*6777b538SAndroid Build Coastguard Worker while (it != events->end()) {
126*6777b538SAndroid Build Coastguard Worker if (kBluetoothEventHashes.contains(it->event_name_hash())) {
127*6777b538SAndroid Build Coastguard Worker it = events->erase(it);
128*6777b538SAndroid Build Coastguard Worker } else {
129*6777b538SAndroid Build Coastguard Worker ++it;
130*6777b538SAndroid Build Coastguard Worker }
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker }
133*6777b538SAndroid Build Coastguard Worker
FilterProto(EventsProto * proto,const base::flat_set<uint64_t> & disallowed_projects)134*6777b538SAndroid Build Coastguard Worker bool FilterProto(EventsProto* proto,
135*6777b538SAndroid Build Coastguard Worker const base::flat_set<uint64_t>& disallowed_projects) {
136*6777b538SAndroid Build Coastguard Worker FilterEvents(proto->mutable_uma_events(), disallowed_projects);
137*6777b538SAndroid Build Coastguard Worker FilterEvents(proto->mutable_events(), disallowed_projects);
138*6777b538SAndroid Build Coastguard Worker return proto->uma_events_size() > 0 || proto->events_size() > 0;
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker
ReadAndDeleteEvents(const base::FilePath & directory,const base::flat_set<uint64_t> & disallowed_projects,bool recording_enabled)141*6777b538SAndroid Build Coastguard Worker EventsProto ReadAndDeleteEvents(
142*6777b538SAndroid Build Coastguard Worker const base::FilePath& directory,
143*6777b538SAndroid Build Coastguard Worker const base::flat_set<uint64_t>& disallowed_projects,
144*6777b538SAndroid Build Coastguard Worker bool recording_enabled) {
145*6777b538SAndroid Build Coastguard Worker base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
146*6777b538SAndroid Build Coastguard Worker base::BlockingType::MAY_BLOCK);
147*6777b538SAndroid Build Coastguard Worker EventsProto result;
148*6777b538SAndroid Build Coastguard Worker if (!base::DirectoryExists(directory)) {
149*6777b538SAndroid Build Coastguard Worker return result;
150*6777b538SAndroid Build Coastguard Worker }
151*6777b538SAndroid Build Coastguard Worker
152*6777b538SAndroid Build Coastguard Worker base::DirReaderPosix dir_reader(directory.value().c_str());
153*6777b538SAndroid Build Coastguard Worker if (!dir_reader.IsValid()) {
154*6777b538SAndroid Build Coastguard Worker VLOG(2) << "Failed to load External Metrics directory: " << directory;
155*6777b538SAndroid Build Coastguard Worker return result;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker
158*6777b538SAndroid Build Coastguard Worker int file_counter = 0;
159*6777b538SAndroid Build Coastguard Worker int dropped_events = 0;
160*6777b538SAndroid Build Coastguard Worker base::flat_map<uint64_t, int> dropped_projects_count, produced_projects_count;
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker while (dir_reader.Next()) {
163*6777b538SAndroid Build Coastguard Worker base::FilePath path = directory.Append(dir_reader.name());
164*6777b538SAndroid Build Coastguard Worker base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_OPEN_ALWAYS);
165*6777b538SAndroid Build Coastguard Worker
166*6777b538SAndroid Build Coastguard Worker // This will fail on '.' and '..' files.
167*6777b538SAndroid Build Coastguard Worker if (!file.IsValid()) {
168*6777b538SAndroid Build Coastguard Worker continue;
169*6777b538SAndroid Build Coastguard Worker }
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker // Ignore any directory.
172*6777b538SAndroid Build Coastguard Worker base::File::Info info;
173*6777b538SAndroid Build Coastguard Worker if (!file.GetInfo(&info) || info.is_directory) {
174*6777b538SAndroid Build Coastguard Worker continue;
175*6777b538SAndroid Build Coastguard Worker }
176*6777b538SAndroid Build Coastguard Worker
177*6777b538SAndroid Build Coastguard Worker // If recording is disabled delete the file.
178*6777b538SAndroid Build Coastguard Worker if (!recording_enabled) {
179*6777b538SAndroid Build Coastguard Worker base::DeleteFile(path);
180*6777b538SAndroid Build Coastguard Worker continue;
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker
183*6777b538SAndroid Build Coastguard Worker ++file_counter;
184*6777b538SAndroid Build Coastguard Worker
185*6777b538SAndroid Build Coastguard Worker std::string proto_str;
186*6777b538SAndroid Build Coastguard Worker int64_t file_size;
187*6777b538SAndroid Build Coastguard Worker EventsProto proto;
188*6777b538SAndroid Build Coastguard Worker
189*6777b538SAndroid Build Coastguard Worker // If an event is abnormally large, ignore it to prevent OOM.
190*6777b538SAndroid Build Coastguard Worker bool fs_ok = base::GetFileSize(path, &file_size);
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker // If file size get is successful, log the file size.
193*6777b538SAndroid Build Coastguard Worker if (fs_ok) {
194*6777b538SAndroid Build Coastguard Worker LogEventFileSizeKB(static_cast<int>(file_size / 1024));
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker
197*6777b538SAndroid Build Coastguard Worker if (!fs_ok || file_size > GetFileSizeByteLimit()) {
198*6777b538SAndroid Build Coastguard Worker base::DeleteFile(path);
199*6777b538SAndroid Build Coastguard Worker continue;
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker bool read_ok = base::ReadFileToString(path, &proto_str) &&
203*6777b538SAndroid Build Coastguard Worker proto.ParseFromString(proto_str);
204*6777b538SAndroid Build Coastguard Worker base::DeleteFile(path);
205*6777b538SAndroid Build Coastguard Worker
206*6777b538SAndroid Build Coastguard Worker // Process all events that were packed in the proto.
207*6777b538SAndroid Build Coastguard Worker ProcessEventProtosProjectCounts(produced_projects_count, proto);
208*6777b538SAndroid Build Coastguard Worker
209*6777b538SAndroid Build Coastguard Worker // There may be too many messages in the directory to hold in-memory.
210*6777b538SAndroid Build Coastguard Worker // This could happen if the process in which Structured metrics resides
211*6777b538SAndroid Build Coastguard Worker // is either crash-looping or taking too long to process externally
212*6777b538SAndroid Build Coastguard Worker // recorded events.
213*6777b538SAndroid Build Coastguard Worker //
214*6777b538SAndroid Build Coastguard Worker // Events will be dropped in that case so that more recent events can be
215*6777b538SAndroid Build Coastguard Worker // processed. Events will be dropped if recording has been disabled.
216*6777b538SAndroid Build Coastguard Worker if (file_counter > GetFileLimitPerScan()) {
217*6777b538SAndroid Build Coastguard Worker ++dropped_events;
218*6777b538SAndroid Build Coastguard Worker
219*6777b538SAndroid Build Coastguard Worker // Process all events that were packed in the proto.
220*6777b538SAndroid Build Coastguard Worker ProcessEventProtosProjectCounts(dropped_projects_count, proto);
221*6777b538SAndroid Build Coastguard Worker continue;
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker if (!read_ok) {
225*6777b538SAndroid Build Coastguard Worker continue;
226*6777b538SAndroid Build Coastguard Worker }
227*6777b538SAndroid Build Coastguard Worker
228*6777b538SAndroid Build Coastguard Worker if (!FilterProto(&proto, disallowed_projects)) {
229*6777b538SAndroid Build Coastguard Worker continue;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker
232*6777b538SAndroid Build Coastguard Worker // MergeFrom performs a copy that could be a move if done manually. But
233*6777b538SAndroid Build Coastguard Worker // all the protos here are expected to be small, so let's keep it simple.
234*6777b538SAndroid Build Coastguard Worker result.mutable_uma_events()->MergeFrom(proto.uma_events());
235*6777b538SAndroid Build Coastguard Worker result.mutable_events()->MergeFrom(proto.events());
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker
238*6777b538SAndroid Build Coastguard Worker if (recording_enabled) {
239*6777b538SAndroid Build Coastguard Worker LogDroppedExternalMetrics(dropped_events);
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker // Log histograms for each project with their appropriate counts.
242*6777b538SAndroid Build Coastguard Worker // If a project isn't seen then it will not be logged.
243*6777b538SAndroid Build Coastguard Worker for (const auto& project_counts : produced_projects_count) {
244*6777b538SAndroid Build Coastguard Worker LogProducedProjectExternalMetrics(
245*6777b538SAndroid Build Coastguard Worker Platform2ProjectName(project_counts.first), project_counts.second);
246*6777b538SAndroid Build Coastguard Worker }
247*6777b538SAndroid Build Coastguard Worker
248*6777b538SAndroid Build Coastguard Worker for (const auto& project_counts : dropped_projects_count) {
249*6777b538SAndroid Build Coastguard Worker LogDroppedProjectExternalMetrics(
250*6777b538SAndroid Build Coastguard Worker Platform2ProjectName(project_counts.first), project_counts.second);
251*6777b538SAndroid Build Coastguard Worker }
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker
254*6777b538SAndroid Build Coastguard Worker LogNumFilesPerExternalMetricsScan(file_counter);
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker MaybeFilterBluetoothEvents(result.mutable_uma_events());
257*6777b538SAndroid Build Coastguard Worker MaybeFilterBluetoothEvents(result.mutable_events());
258*6777b538SAndroid Build Coastguard Worker
259*6777b538SAndroid Build Coastguard Worker return result;
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker } // namespace
263*6777b538SAndroid Build Coastguard Worker
ExternalMetrics(const base::FilePath & events_directory,const base::TimeDelta & collection_interval,MetricsCollectedCallback callback)264*6777b538SAndroid Build Coastguard Worker ExternalMetrics::ExternalMetrics(const base::FilePath& events_directory,
265*6777b538SAndroid Build Coastguard Worker const base::TimeDelta& collection_interval,
266*6777b538SAndroid Build Coastguard Worker MetricsCollectedCallback callback)
267*6777b538SAndroid Build Coastguard Worker : events_directory_(events_directory),
268*6777b538SAndroid Build Coastguard Worker collection_interval_(collection_interval),
269*6777b538SAndroid Build Coastguard Worker callback_(std::move(callback)),
270*6777b538SAndroid Build Coastguard Worker task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
271*6777b538SAndroid Build Coastguard Worker {base::TaskPriority::BEST_EFFORT, base::MayBlock(),
272*6777b538SAndroid Build Coastguard Worker base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
273*6777b538SAndroid Build Coastguard Worker ScheduleCollector();
274*6777b538SAndroid Build Coastguard Worker CacheDisallowedProjectsSet();
275*6777b538SAndroid Build Coastguard Worker }
276*6777b538SAndroid Build Coastguard Worker
277*6777b538SAndroid Build Coastguard Worker ExternalMetrics::~ExternalMetrics() = default;
278*6777b538SAndroid Build Coastguard Worker
CollectEventsAndReschedule()279*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::CollectEventsAndReschedule() {
280*6777b538SAndroid Build Coastguard Worker CollectEvents();
281*6777b538SAndroid Build Coastguard Worker ScheduleCollector();
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker
ScheduleCollector()284*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::ScheduleCollector() {
285*6777b538SAndroid Build Coastguard Worker base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
286*6777b538SAndroid Build Coastguard Worker FROM_HERE,
287*6777b538SAndroid Build Coastguard Worker base::BindOnce(&ExternalMetrics::CollectEventsAndReschedule,
288*6777b538SAndroid Build Coastguard Worker weak_factory_.GetWeakPtr()),
289*6777b538SAndroid Build Coastguard Worker collection_interval_);
290*6777b538SAndroid Build Coastguard Worker }
291*6777b538SAndroid Build Coastguard Worker
CollectEvents()292*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::CollectEvents() {
293*6777b538SAndroid Build Coastguard Worker task_runner_->PostTaskAndReplyWithResult(
294*6777b538SAndroid Build Coastguard Worker FROM_HERE,
295*6777b538SAndroid Build Coastguard Worker base::BindOnce(&ReadAndDeleteEvents, events_directory_,
296*6777b538SAndroid Build Coastguard Worker disallowed_projects_, recording_enabled_),
297*6777b538SAndroid Build Coastguard Worker base::BindOnce(callback_));
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker
CacheDisallowedProjectsSet()300*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::CacheDisallowedProjectsSet() {
301*6777b538SAndroid Build Coastguard Worker const std::string& disallowed_list = GetDisabledProjects();
302*6777b538SAndroid Build Coastguard Worker if (disallowed_list.empty()) {
303*6777b538SAndroid Build Coastguard Worker return;
304*6777b538SAndroid Build Coastguard Worker }
305*6777b538SAndroid Build Coastguard Worker
306*6777b538SAndroid Build Coastguard Worker for (const auto& value :
307*6777b538SAndroid Build Coastguard Worker base::SplitString(disallowed_list, ",", base::TRIM_WHITESPACE,
308*6777b538SAndroid Build Coastguard Worker base::SPLIT_WANT_NONEMPTY)) {
309*6777b538SAndroid Build Coastguard Worker uint64_t project_name_hash;
310*6777b538SAndroid Build Coastguard Worker // Parse the string and keep only perfect conversions.
311*6777b538SAndroid Build Coastguard Worker if (base::StringToUint64(value, &project_name_hash)) {
312*6777b538SAndroid Build Coastguard Worker disallowed_projects_.insert(project_name_hash);
313*6777b538SAndroid Build Coastguard Worker }
314*6777b538SAndroid Build Coastguard Worker }
315*6777b538SAndroid Build Coastguard Worker }
316*6777b538SAndroid Build Coastguard Worker
AddDisallowedProjectForTest(uint64_t project_name_hash)317*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::AddDisallowedProjectForTest(uint64_t project_name_hash) {
318*6777b538SAndroid Build Coastguard Worker disallowed_projects_.insert(project_name_hash);
319*6777b538SAndroid Build Coastguard Worker }
320*6777b538SAndroid Build Coastguard Worker
EnableRecording()321*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::EnableRecording() {
322*6777b538SAndroid Build Coastguard Worker recording_enabled_ = true;
323*6777b538SAndroid Build Coastguard Worker }
324*6777b538SAndroid Build Coastguard Worker
DisableRecording()325*6777b538SAndroid Build Coastguard Worker void ExternalMetrics::DisableRecording() {
326*6777b538SAndroid Build Coastguard Worker recording_enabled_ = false;
327*6777b538SAndroid Build Coastguard Worker }
328*6777b538SAndroid Build Coastguard Worker
329*6777b538SAndroid Build Coastguard Worker } // namespace metrics::structured
330