xref: /aosp_15_r20/external/cronet/components/metrics/structured/external_metrics.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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