• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_METRICS_STRUCTURED_EXTERNAL_METRICS_H_
6 #define COMPONENTS_METRICS_STRUCTURED_EXTERNAL_METRICS_H_
7 
8 #include "base/containers/flat_set.h"
9 #include "base/files/file_path.h"
10 #include "base/functional/callback.h"
11 #include "base/memory/scoped_refptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/task/sequenced_task_runner.h"
14 #include "base/time/time.h"
15 
16 namespace metrics::structured {
17 
18 class EventsProto;
19 class ExternalMetricsTest;
20 
21 // ExternalMetrics reads structured metrics saved by ChromeOS and uploads them
22 // to the UMA server on its behalf. This is structured metrics' equivalent of
23 // `ash::ExternalMetrics`.
24 //
25 // When a call to CollectEvents() is done, events in that directory will be
26 // added to StructuredMetricsRecorder. However, if the user has disabled upload,
27 // then all events will be dropped and deleted.
28 //
29 // Chrome periodically reads a directory of protos and adds their content into
30 // the StructuredMetricProvider's regular metrics upload. After reading each
31 // file, it is deleted. Chrome and ChromeOS use flock to prevent concurrent
32 // read/writes.
33 class ExternalMetrics {
34  public:
35   using MetricsCollectedCallback =
36       base::RepeatingCallback<void(const EventsProto&)>;
37 
38   ExternalMetrics(const base::FilePath& events_directory,
39                   const base::TimeDelta& collection_interval,
40                   MetricsCollectedCallback callback);
41   ~ExternalMetrics();
42   ExternalMetrics(const ExternalMetrics&) = delete;
43   ExternalMetrics& operator=(const ExternalMetrics&) = delete;
44 
45   // Adds a project to the disallowed list for testing.
46   void AddDisallowedProjectForTest(uint64_t project_name_hash);
47 
48   void EnableRecording();
49   void DisableRecording();
50 
51  private:
52   friend class ExternalMetricsTest;
53 
54   void ScheduleCollector();
55   void CollectEventsAndReschedule();
56 
57   // Events are collected from |events_directory|. Each file is processed by:
58   //
59   //    1. Stat on a file to see if it contains any events or if
60   //       something in ChromeOS has already deleted the file.
61   //    2. Obtains a flock.
62   //    3. File is processed and read into memory.
63   //    4. File is deleted.
64   //    5. Flock is released.
65   //
66   // The above is done to avoid reading files mid-write from ChromeOS and having
67   // ChromeOS write files after they were marked for deletion by Chrome.
68   //
69   // Files will be ignored if there is failure to obtain the flock or get the
70   // file descriptor.
71   //
72   // Files will be dropped when an event file exceeds a fixed threshold provided
73   // by GetFileSizeByteLimit(). Files will also be dropped if there are too many
74   // event files existing on the current iteration provided by
75   // GetFileLimitPerScan().
76   void CollectEvents();
77 
78   // Builds a cache of disallow projects from the Finch controlled variable.
79   void CacheDisallowedProjectsSet();
80 
81   bool recording_enabled_ = false;
82 
83   const base::FilePath events_directory_;
84   const base::TimeDelta collection_interval_;
85   MetricsCollectedCallback callback_;
86 
87   // A set of projects that are not allowed to be recorded. This is a cache of
88   // GetDisabledProjects().
89   base::flat_set<uint64_t> disallowed_projects_;
90 
91   scoped_refptr<base::SequencedTaskRunner> task_runner_;
92   base::WeakPtrFactory<ExternalMetrics> weak_factory_{this};
93 };
94 
95 }  // namespace metrics::structured
96 
97 #endif  // COMPONENTS_METRICS_STRUCTURED_EXTERNAL_METRICS_H_
98