bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors. All rights reserved. |
| 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_FILE_METRICS_PROVIDER_H_ |
| 6 | #define COMPONENTS_METRICS_FILE_METRICS_PROVIDER_H_ |
| 7 | |
| 8 | #include <list> |
dcheng | d99c42a | 2016-04-21 21:54:13 | [diff] [blame] | 9 | #include <memory> |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 10 | #include <string> |
| 11 | |
| 12 | #include "base/callback.h" |
| 13 | #include "base/files/file_path.h" |
| 14 | #include "base/gtest_prod_util.h" |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 15 | #include "base/memory/weak_ptr.h" |
bcwhite | 9075a09 | 2017-02-01 01:58:56 | [diff] [blame] | 16 | #include "base/metrics/statistics_recorder.h" |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 17 | #include "base/threading/thread_checker.h" |
| 18 | #include "base/time/time.h" |
| 19 | #include "components/metrics/metrics_provider.h" |
| 20 | |
| 21 | class PrefRegistrySimple; |
| 22 | class PrefService; |
| 23 | |
| 24 | namespace base { |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 25 | class TaskRunner; |
| 26 | } |
| 27 | |
| 28 | namespace metrics { |
| 29 | |
| 30 | // FileMetricsProvider gathers and logs histograms written to files on disk. |
| 31 | // Any number of files can be registered and will be polled once per upload |
| 32 | // cycle (at startup and periodically thereafter -- about every 30 minutes |
| 33 | // for desktop) for data to send. |
bcwhite | 9075a09 | 2017-02-01 01:58:56 | [diff] [blame] | 34 | class FileMetricsProvider : public MetricsProvider, |
| 35 | public base::StatisticsRecorder::HistogramProvider { |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 36 | public: |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 37 | enum SourceType { |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 38 | // "Atomic" files are a collection of histograms that are written |
| 39 | // completely in a single atomic operation (typically a write followed |
| 40 | // by an atomic rename) and the file is never updated again except to |
| 41 | // be replaced by a completely new set of histograms. This is the only |
| 42 | // option that can be used if the file is not writeable by *this* |
bcwhite | 48d0e749 | 2016-05-25 01:59:05 | [diff] [blame] | 43 | // process. Once the file has been read, an attempt will be made to |
| 44 | // delete it thus providing some measure of safety should different |
| 45 | // instantiations (such as by different users of a system-level install) |
| 46 | // try to read it. In case the delete operation fails, this class |
| 47 | // persistently tracks the last-modified time of the file so it will |
| 48 | // not be read a second time. |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 49 | SOURCE_HISTOGRAMS_ATOMIC_FILE, |
| 50 | |
| 51 | // A directory of atomic PMA files. This handles a directory in which |
| 52 | // files of metrics are atomically added. Only files ending with ".pma" |
| 53 | // will be read. They are read according to their last-modified time and |
| 54 | // never read more that once (unless they change). Only one file will |
| 55 | // be read per reporting cycle. Filenames that start with a dot (.) or |
| 56 | // an underscore (_) are ignored so temporary files (perhaps created by |
| 57 | // the ImportantFileWriter) will not get read. Files that have been |
| 58 | // read will be attempted to be deleted; should those files not be |
| 59 | // deletable by this process, it is the reponsibility of the producer |
| 60 | // to keep the directory pruned in some manner. |
| 61 | SOURCE_HISTOGRAMS_ATOMIC_DIR, |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 62 | |
| 63 | // "Active" files may be open by one or more other processes and updated |
| 64 | // at any time with new samples or new histograms. Such files may also be |
| 65 | // inactive for any period of time only to be opened again and have new |
| 66 | // data written to them. The file should probably never be deleted because |
| 67 | // there would be no guarantee that the data has been reported. |
| 68 | // TODO(bcwhite): Enable when read/write mem-mapped files are supported. |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 69 | SOURCE_HISTOGRAMS_ACTIVE_FILE, |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 70 | }; |
| 71 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 72 | enum SourceAssociation { |
bcwhite | 65e57d0 | 2016-05-13 14:39:40 | [diff] [blame] | 73 | // Associates the metrics in the file with the current run of the browser. |
| 74 | // The reporting will take place as part of the normal logging of |
| 75 | // histograms. |
| 76 | ASSOCIATE_CURRENT_RUN, |
| 77 | |
| 78 | // Associates the metrics in the file with the previous run of the browesr. |
| 79 | // The reporting will take place as part of the "stability" histograms. |
| 80 | // This is important when metrics are dumped as part of a crash of the |
| 81 | // previous run. This can only be used with FILE_HISTOGRAMS_ATOMIC. |
| 82 | ASSOCIATE_PREVIOUS_RUN, |
| 83 | }; |
| 84 | |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 85 | FileMetricsProvider(const scoped_refptr<base::TaskRunner>& task_runner, |
| 86 | PrefService* local_state); |
| 87 | ~FileMetricsProvider() override; |
| 88 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 89 | // Indicates a file or directory to be monitored and how the file or files |
| 90 | // within that directory are used. Because some metadata may need to persist |
| 91 | // across process restarts, preferences entries are used based on the |
| 92 | // |prefs_key| name. Call RegisterPrefs() with the same name to create the |
bcwhite | 4ff719b | 2017-03-14 14:05:42 | [diff] [blame] | 93 | // necessary keys in advance. Set |prefs_key| empty (nullptr will work) if |
| 94 | // no persistence is required. ACTIVE files shouldn't have a pref key as |
| 95 | // they update internal state about what has been previously sent. |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 96 | void RegisterSource(const base::FilePath& path, |
| 97 | SourceType type, |
| 98 | SourceAssociation source_association, |
| 99 | const base::StringPiece prefs_key); |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 100 | |
| 101 | // Registers all necessary preferences for maintaining persistent state |
| 102 | // about a monitored file across process restarts. The |prefs_key| is |
| 103 | // typically the filename. |
| 104 | static void RegisterPrefs(PrefRegistrySimple* prefs, |
| 105 | const base::StringPiece prefs_key); |
| 106 | |
| 107 | private: |
| 108 | friend class FileMetricsProviderTest; |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 109 | |
| 110 | // The different results that can occur accessing a file. |
| 111 | enum AccessResult { |
| 112 | // File was successfully mapped. |
| 113 | ACCESS_RESULT_SUCCESS, |
| 114 | |
| 115 | // File does not exist. |
| 116 | ACCESS_RESULT_DOESNT_EXIST, |
| 117 | |
| 118 | // File exists but not modified since last read. |
| 119 | ACCESS_RESULT_NOT_MODIFIED, |
| 120 | |
| 121 | // File is not valid: is a directory or zero-size. |
| 122 | ACCESS_RESULT_INVALID_FILE, |
| 123 | |
| 124 | // System could not map file into memory. |
| 125 | ACCESS_RESULT_SYSTEM_MAP_FAILURE, |
| 126 | |
| 127 | // File had invalid contents. |
| 128 | ACCESS_RESULT_INVALID_CONTENTS, |
| 129 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 130 | // File could not be opened. |
| 131 | ACCESS_RESULT_NO_OPEN, |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 132 | |
bcwhite | 42561dc | 2017-03-16 18:35:24 | [diff] [blame] | 133 | // File contents were internally deleted. |
| 134 | ACCESS_RESULT_MEMORY_DELETED, |
| 135 | |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 136 | ACCESS_RESULT_MAX |
| 137 | }; |
| 138 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 139 | // Information about sources being monitored; defined and used exclusively |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 140 | // inside the .cc file. |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 141 | struct SourceInfo; |
| 142 | using SourceInfoList = std::list<std::unique_ptr<SourceInfo>>; |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 143 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 144 | // Looks for the next file to read within a directory. Returns true if a |
| 145 | // file was found. This is part of CheckAndMapNewMetricSourcesOnTaskRunner |
| 146 | // and so runs on an thread capable of I/O. The |source| structure will |
| 147 | // be internally updated to indicate the next file to be read. |
| 148 | static bool LocateNextFileInDirectory(SourceInfo* source); |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 149 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 150 | // Checks a list of sources (on a task-runner allowed to do I/O) and merge |
| 151 | // any data found within them. |
| 152 | static void CheckAndMergeMetricSourcesOnTaskRunner(SourceInfoList* sources); |
| 153 | |
| 154 | // Checks a single source and maps it into memory. |
| 155 | static AccessResult CheckAndMapMetricSource(SourceInfo* source); |
| 156 | |
| 157 | // Merges all of the histograms from a |source| to the StatisticsRecorder. |
| 158 | static void MergeHistogramDeltasFromSource(SourceInfo* source); |
| 159 | |
| 160 | // Records all histograms from a given source via a snapshot-manager. |
| 161 | static void RecordHistogramSnapshotsFromSource( |
| 162 | base::HistogramSnapshotManager* snapshot_manager, |
| 163 | SourceInfo* source); |
bcwhite | 48d0e749 | 2016-05-25 01:59:05 | [diff] [blame] | 164 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 165 | // Creates a task to check all monitored sources for updates. |
| 166 | void ScheduleSourcesCheck(); |
| 167 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 168 | // Takes a list of sources checked by an external task and determines what |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 169 | // to do with each. |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 170 | void RecordSourcesChecked(SourceInfoList* checked); |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 171 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 172 | // Schedules the deletion of a file in the background using the task-runner. |
| 173 | void DeleteFileAsync(const base::FilePath& path); |
| 174 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 175 | // Updates the persistent state information to show a source as being read. |
bcwhite | 48d0e749 | 2016-05-25 01:59:05 | [diff] [blame] | 176 | void RecordSourceAsRead(SourceInfo* source); |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 177 | |
| 178 | // metrics::MetricsDataProvider: |
| 179 | void OnDidCreateMetricsLog() override; |
bcwhite | 65e57d0 | 2016-05-13 14:39:40 | [diff] [blame] | 180 | bool HasInitialStabilityMetrics() override; |
bcwhite | 65e57d0 | 2016-05-13 14:39:40 | [diff] [blame] | 181 | void RecordInitialHistogramSnapshots( |
| 182 | base::HistogramSnapshotManager* snapshot_manager) override; |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 183 | |
bcwhite | 9075a09 | 2017-02-01 01:58:56 | [diff] [blame] | 184 | // base::StatisticsRecorder::HistogramProvider: |
| 185 | void MergeHistogramDeltas() override; |
| 186 | |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 187 | // A task-runner capable of performing I/O. |
| 188 | scoped_refptr<base::TaskRunner> task_runner_; |
| 189 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 190 | // A list of sources not currently active that need to be checked for changes. |
| 191 | SourceInfoList sources_to_check_; |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 192 | |
bcwhite | 2a27d74 | 2016-06-10 15:47:05 | [diff] [blame] | 193 | // A list of currently active sources to be merged when required. |
| 194 | SourceInfoList sources_mapped_; |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 195 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 196 | // A list of sources for a previous run. These are held separately because |
bcwhite | 65e57d0 | 2016-05-13 14:39:40 | [diff] [blame] | 197 | // they are not subject to the periodic background checking that handles |
| 198 | // metrics for the current run. |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 199 | SourceInfoList sources_for_previous_run_; |
bcwhite | 65e57d0 | 2016-05-13 14:39:40 | [diff] [blame] | 200 | |
bcwhite | 0d2c382 | 2016-05-16 15:17:12 | [diff] [blame] | 201 | // The preferences-service used to store persistent state about sources. |
bcwhite | 34c6bbf | 2016-02-19 22:14:46 | [diff] [blame] | 202 | PrefService* pref_service_; |
| 203 | |
| 204 | base::ThreadChecker thread_checker_; |
| 205 | base::WeakPtrFactory<FileMetricsProvider> weak_factory_; |
| 206 | |
| 207 | DISALLOW_COPY_AND_ASSIGN(FileMetricsProvider); |
| 208 | }; |
| 209 | |
| 210 | } // namespace metrics |
| 211 | |
| 212 | #endif // COMPONENTS_METRICS_FILE_METRICS_PROVIDER_H_ |