• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 // This file defines a service that collects information about the user
6 // experience in order to help improve future versions of the app.
7 
8 #ifndef COMPONENTS_METRICS_METRICS_SERVICE_H_
9 #define COMPONENTS_METRICS_METRICS_SERVICE_H_
10 
11 #include <map>
12 #include <string>
13 #include <vector>
14 
15 #include "base/basictypes.h"
16 #include "base/gtest_prod_util.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/metrics/field_trial.h"
21 #include "base/metrics/histogram_flattener.h"
22 #include "base/metrics/histogram_snapshot_manager.h"
23 #include "base/metrics/user_metrics.h"
24 #include "base/observer_list.h"
25 #include "base/strings/string16.h"
26 #include "base/threading/thread_checker.h"
27 #include "base/time/time.h"
28 #include "components/metrics/metrics_log.h"
29 #include "components/metrics/metrics_log_manager.h"
30 #include "components/metrics/metrics_provider.h"
31 #include "components/metrics/metrics_service_observer.h"
32 #include "components/variations/active_field_trials.h"
33 
34 class MetricsReportingScheduler;
35 class PrefService;
36 class PrefRegistrySimple;
37 
38 namespace base {
39 class DictionaryValue;
40 class HistogramSamples;
41 class MessageLoopProxy;
42 class PrefService;
43 }
44 
45 namespace variations {
46 struct ActiveGroupId;
47 }
48 
49 namespace metrics {
50 class MetricsLogUploader;
51 class MetricsServiceClient;
52 class MetricsStateManager;
53 }
54 
55 namespace net {
56 class URLFetcher;
57 }
58 
59 // A Field Trial and its selected group, which represent a particular
60 // Chrome configuration state. For example, the trial name could map to
61 // a preference name, and the group name could map to a preference value.
62 struct SyntheticTrialGroup {
63  public:
64   ~SyntheticTrialGroup();
65 
66   variations::ActiveGroupId id;
67   base::TimeTicks start_time;
68 
69  private:
70   friend class MetricsService;
71   FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
72 
73   // This constructor is private specifically so as to control which code is
74   // able to access it. New code that wishes to use it should be added as a
75   // friend class.
76   SyntheticTrialGroup(uint32 trial, uint32 group);
77 };
78 
79 class MetricsService : public base::HistogramFlattener {
80  public:
81   // The execution phase of the browser.
82   enum ExecutionPhase {
83     UNINITIALIZED_PHASE = 0,
84     START_METRICS_RECORDING = 100,
85     CREATE_PROFILE = 200,
86     STARTUP_TIMEBOMB_ARM = 300,
87     THREAD_WATCHER_START = 400,
88     MAIN_MESSAGE_LOOP_RUN = 500,
89     SHUTDOWN_TIMEBOMB_ARM = 600,
90     SHUTDOWN_COMPLETE = 700,
91   };
92 
93   // Creates the MetricsService with the given |state_manager|, |client|, and
94   // |local_state|.  Does not take ownership of the paramaters; instead stores
95   // a weak pointer to each. Caller should ensure that the parameters are valid
96   // for the lifetime of this class.
97   MetricsService(metrics::MetricsStateManager* state_manager,
98                  metrics::MetricsServiceClient* client,
99                  PrefService* local_state);
100   virtual ~MetricsService();
101 
102   // Initializes metrics recording state. Updates various bookkeeping values in
103   // prefs and sets up the scheduler. This is a separate function rather than
104   // being done by the constructor so that field trials could be created before
105   // this is run.
106   void InitializeMetricsRecordingState();
107 
108   // Starts the metrics system, turning on recording and uploading of metrics.
109   // Should be called when starting up with metrics enabled, or when metrics
110   // are turned on.
111   void Start();
112 
113   // If metrics reporting is enabled, starts the metrics service. Returns
114   // whether the metrics service was started.
115   bool StartIfMetricsReportingEnabled();
116 
117   // Starts the metrics system in a special test-only mode. Metrics won't ever
118   // be uploaded or persisted in this mode, but metrics will be recorded in
119   // memory.
120   void StartRecordingForTests();
121 
122   // Shuts down the metrics system. Should be called at shutdown, or if metrics
123   // are turned off.
124   void Stop();
125 
126   // Enable/disable transmission of accumulated logs and crash reports (dumps).
127   // Calling Start() automatically enables reporting, but sending is
128   // asyncronous so this can be called immediately after Start() to prevent
129   // any uploading.
130   void EnableReporting();
131   void DisableReporting();
132 
133   // Returns the client ID for this client, or the empty string if metrics
134   // recording is not currently running.
135   std::string GetClientId();
136 
137   // Returns the preferred entropy provider used to seed persistent activities
138   // based on whether or not metrics reporting will be permitted on this client.
139   //
140   // If metrics reporting is enabled, this method returns an entropy provider
141   // that has a high source of entropy, partially based on the client ID.
142   // Otherwise, it returns an entropy provider that is based on a low entropy
143   // source.
144   scoped_ptr<const base::FieldTrial::EntropyProvider> CreateEntropyProvider();
145 
146   // At startup, prefs needs to be called with a list of all the pref names and
147   // types we'll be using.
148   static void RegisterPrefs(PrefRegistrySimple* registry);
149 
150   // HistogramFlattener:
151   virtual void RecordDelta(const base::HistogramBase& histogram,
152                            const base::HistogramSamples& snapshot) OVERRIDE;
153   virtual void InconsistencyDetected(
154       base::HistogramBase::Inconsistency problem) OVERRIDE;
155   virtual void UniqueInconsistencyDetected(
156       base::HistogramBase::Inconsistency problem) OVERRIDE;
157   virtual void InconsistencyDetectedInLoggedCount(int amount) OVERRIDE;
158 
159   // This should be called when the application is not idle, i.e. the user seems
160   // to be interacting with the application.
161   void OnApplicationNotIdle();
162 
163   // Invoked when we get a WM_SESSIONEND. This places a value in prefs that is
164   // reset when RecordCompletedSessionEnd is invoked.
165   void RecordStartOfSessionEnd();
166 
167   // This should be called when the application is shutting down. It records
168   // that session end was successful.
169   void RecordCompletedSessionEnd();
170 
171 #if defined(OS_ANDROID) || defined(OS_IOS)
172   // Called when the application is going into background mode.
173   void OnAppEnterBackground();
174 
175   // Called when the application is coming out of background mode.
176   void OnAppEnterForeground();
177 #else
178   // Set the dirty flag, which will require a later call to LogCleanShutdown().
179   static void LogNeedForCleanShutdown(PrefService* local_state);
180 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
181 
182   static void SetExecutionPhase(ExecutionPhase execution_phase,
183                                 PrefService* local_state);
184 
185   // Saves in the preferences if the crash report registration was successful.
186   // This count is eventually send via UMA logs.
187   void RecordBreakpadRegistration(bool success);
188 
189   // Saves in the preferences if the browser is running under a debugger.
190   // This count is eventually send via UMA logs.
191   void RecordBreakpadHasDebugger(bool has_debugger);
192 
193   bool recording_active() const;
194   bool reporting_active() const;
195 
196   // Redundant test to ensure that we are notified of a clean exit.
197   // This value should be true when process has completed shutdown.
198   static bool UmaMetricsProperlyShutdown();
199 
200   // Registers a field trial name and group to be used to annotate a UMA report
201   // with a particular Chrome configuration state. A UMA report will be
202   // annotated with this trial group if and only if all events in the report
203   // were created after the trial is registered. Only one group name may be
204   // registered at a time for a given trial_name. Only the last group name that
205   // is registered for a given trial name will be recorded. The values passed
206   // in must not correspond to any real field trial in the code.
207   // To use this method, SyntheticTrialGroup should friend your class.
208   void RegisterSyntheticFieldTrial(const SyntheticTrialGroup& trial_group);
209 
210   // Register the specified |provider| to provide additional metrics into the
211   // UMA log. Should be called during MetricsService initialization only.
212   void RegisterMetricsProvider(scoped_ptr<metrics::MetricsProvider> provider);
213 
214   // Check if this install was cloned or imaged from another machine. If a
215   // clone is detected, reset the client id and low entropy source. This
216   // should not be called more than once.
217   void CheckForClonedInstall(
218       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
219 
220  protected:
221   // Exposed for testing.
log_manager()222   metrics::MetricsLogManager* log_manager() { return &log_manager_; }
223 
224  private:
225   // The MetricsService has a lifecycle that is stored as a state.
226   // See metrics_service.cc for description of this lifecycle.
227   enum State {
228     INITIALIZED,                    // Constructor was called.
229     INIT_TASK_SCHEDULED,            // Waiting for deferred init tasks to
230                                     // complete.
231     INIT_TASK_DONE,                 // Waiting for timer to send initial log.
232     SENDING_INITIAL_STABILITY_LOG,  // Initial stability log being sent.
233     SENDING_INITIAL_METRICS_LOG,    // Initial metrics log being sent.
234     SENDING_OLD_LOGS,               // Sending unsent logs from last session.
235     SENDING_CURRENT_LOGS,           // Sending ongoing logs as they accrue.
236   };
237 
238   enum ShutdownCleanliness {
239     CLEANLY_SHUTDOWN = 0xdeadbeef,
240     NEED_TO_SHUTDOWN = ~CLEANLY_SHUTDOWN
241   };
242 
243   typedef std::vector<SyntheticTrialGroup> SyntheticTrialGroups;
244 
245   // Calls into the client to start metrics gathering.
246   void StartGatheringMetrics();
247 
248   // Callback that moves the state to INIT_TASK_DONE. When this is called, the
249   // state should be INIT_TASK_SCHEDULED.
250   void FinishedGatheringInitialMetrics();
251 
252   void OnUserAction(const std::string& action);
253 
254   // Get the amount of uptime since this process started and since the last
255   // call to this function.  Also updates the cumulative uptime metric (stored
256   // as a pref) for uninstall.  Uptimes are measured using TimeTicks, which
257   // guarantees that it is monotonic and does not jump if the user changes
258   // his/her clock.  The TimeTicks implementation also makes the clock not
259   // count time the computer is suspended.
260   void GetUptimes(PrefService* pref,
261                   base::TimeDelta* incremental_uptime,
262                   base::TimeDelta* uptime);
263 
264   // Turns recording on or off.
265   // DisableRecording() also forces a persistent save of logging state (if
266   // anything has been recorded, or transmitted).
267   void EnableRecording();
268   void DisableRecording();
269 
270   // If in_idle is true, sets idle_since_last_transmission to true.
271   // If in_idle is false and idle_since_last_transmission_ is true, sets
272   // idle_since_last_transmission to false and starts the timer (provided
273   // starting the timer is permitted).
274   void HandleIdleSinceLastTransmission(bool in_idle);
275 
276   // Set up client ID, session ID, etc.
277   void InitializeMetricsState();
278 
279   // Registers/unregisters |observer| to receive MetricsLog notifications.
280   void AddObserver(MetricsServiceObserver* observer);
281   void RemoveObserver(MetricsServiceObserver* observer);
282   void NotifyOnDidCreateMetricsLog();
283 
284   // Schedule the next save of LocalState information.  This is called
285   // automatically by the task that performs each save to schedule the next one.
286   void ScheduleNextStateSave();
287 
288   // Save the LocalState information immediately. This should not be called by
289   // anybody other than the scheduler to avoid doing too many writes. When you
290   // make a change, call ScheduleNextStateSave() instead.
291   void SaveLocalState();
292 
293   // Opens a new log for recording user experience metrics.
294   void OpenNewLog();
295 
296   // Closes out the current log after adding any last information.
297   void CloseCurrentLog();
298 
299   // Pushes the text of the current and staged logs into persistent storage.
300   // Called when Chrome shuts down.
301   void PushPendingLogsToPersistentStorage();
302 
303   // Ensures that scheduler is running, assuming the current settings are such
304   // that metrics should be reported. If not, this is a no-op.
305   void StartSchedulerIfNecessary();
306 
307   // Starts the process of uploading metrics data.
308   void StartScheduledUpload();
309 
310   // Called by the client when final log info collection is complete.
311   void OnFinalLogInfoCollectionDone();
312 
313   // Either closes the current log or creates and closes the initial log
314   // (depending on |state_|), and stages it for upload.
315   void StageNewLog();
316 
317   // Prepares the initial stability log, which is only logged when the previous
318   // run of Chrome crashed.  This log contains any stability metrics left over
319   // from that previous run, and only these stability metrics.  It uses the
320   // system profile from the previous session.
321   void PrepareInitialStabilityLog();
322 
323   // Prepares the initial metrics log, which includes startup histograms and
324   // profiler data, as well as incremental stability-related metrics.
325   void PrepareInitialMetricsLog();
326 
327   // Uploads the currently staged log (which must be non-null).
328   void SendStagedLog();
329 
330   // Called after transmission completes (either successfully or with failure).
331   void OnLogUploadComplete(int response_code);
332 
333   // Reads, increments and then sets the specified integer preference.
334   void IncrementPrefValue(const char* path);
335 
336   // Reads, increments and then sets the specified long preference that is
337   // stored as a string.
338   void IncrementLongPrefsValue(const char* path);
339 
340   // Records that the browser was shut down cleanly.
341   void LogCleanShutdown();
342 
343   // Records state that should be periodically saved, like uptime and
344   // buffered plugin stability statistics.
345   void RecordCurrentState(PrefService* pref);
346 
347   // Checks whether events should currently be logged.
348   bool ShouldLogEvents();
349 
350   // Sets the value of the specified path in prefs and schedules a save.
351   void RecordBooleanPrefValue(const char* path, bool value);
352 
353   // Returns a list of synthetic field trials that were active for the entire
354   // duration of the current log.
355   void GetCurrentSyntheticFieldTrials(
356       std::vector<variations::ActiveGroupId>* synthetic_trials);
357 
358   // Creates a new MetricsLog instance with the given |log_type|.
359   scoped_ptr<MetricsLog> CreateLog(MetricsLog::LogType log_type);
360 
361   // Record complete list of histograms into the current log.
362   // Called when we close a log.
363   void RecordCurrentHistograms();
364 
365   // Record complete list of stability histograms into the current log,
366   // i.e., histograms with the |kUmaStabilityHistogramFlag| flag set.
367   void RecordCurrentStabilityHistograms();
368 
369   // Manager for the various in-flight logs.
370   metrics::MetricsLogManager log_manager_;
371 
372   // |histogram_snapshot_manager_| prepares histogram deltas for transmission.
373   base::HistogramSnapshotManager histogram_snapshot_manager_;
374 
375   // Used to manage various metrics reporting state prefs, such as client id,
376   // low entropy source and whether metrics reporting is enabled. Weak pointer.
377   metrics::MetricsStateManager* const state_manager_;
378 
379   // Used to interact with the embedder. Weak pointer; must outlive |this|
380   // instance.
381   metrics::MetricsServiceClient* const client_;
382 
383   // Registered metrics providers.
384   ScopedVector<metrics::MetricsProvider> metrics_providers_;
385 
386   PrefService* local_state_;
387 
388   base::ActionCallback action_callback_;
389 
390   // Indicate whether recording and reporting are currently happening.
391   // These should not be set directly, but by calling SetRecording and
392   // SetReporting.
393   bool recording_active_;
394   bool reporting_active_;
395 
396   // Indicate whether test mode is enabled, where the initial log should never
397   // be cut, and logs are neither persisted nor uploaded.
398   bool test_mode_active_;
399 
400   // The progression of states made by the browser are recorded in the following
401   // state.
402   State state_;
403 
404   // Whether the initial stability log has been recorded during startup.
405   bool has_initial_stability_log_;
406 
407   // The initial metrics log, used to record startup metrics (histograms and
408   // profiler data). Note that if a crash occurred in the previous session, an
409   // initial stability log may be sent before this.
410   scoped_ptr<MetricsLog> initial_metrics_log_;
411 
412   // Instance of the helper class for uploading logs.
413   scoped_ptr<metrics::MetricsLogUploader> log_uploader_;
414 
415   // Whether there is a current log upload in progress.
416   bool log_upload_in_progress_;
417 
418   // Whether the MetricsService object has received any notifications since
419   // the last time a transmission was sent.
420   bool idle_since_last_transmission_;
421 
422   // A number that identifies the how many times the app has been launched.
423   int session_id_;
424 
425   // Weak pointers factory used to post task on different threads. All weak
426   // pointers managed by this factory have the same lifetime as MetricsService.
427   base::WeakPtrFactory<MetricsService> self_ptr_factory_;
428 
429   // Weak pointers factory used for saving state. All weak pointers managed by
430   // this factory are invalidated in ScheduleNextStateSave.
431   base::WeakPtrFactory<MetricsService> state_saver_factory_;
432 
433   // The scheduler for determining when uploads should happen.
434   scoped_ptr<MetricsReportingScheduler> scheduler_;
435 
436   // Stores the time of the first call to |GetUptimes()|.
437   base::TimeTicks first_updated_time_;
438 
439   // Stores the time of the last call to |GetUptimes()|.
440   base::TimeTicks last_updated_time_;
441 
442   // Execution phase the browser is in.
443   static ExecutionPhase execution_phase_;
444 
445   // Reduntant marker to check that we completed our shutdown, and set the
446   // exited-cleanly bit in the prefs.
447   static ShutdownCleanliness clean_shutdown_status_;
448 
449   // Field trial groups that map to Chrome configuration states.
450   SyntheticTrialGroups synthetic_trial_groups_;
451 
452   ObserverList<MetricsServiceObserver> observers_;
453 
454   // Confirms single-threaded access to |observers_| in debug builds.
455   base::ThreadChecker thread_checker_;
456 
457   friend class MetricsServiceAccessor;
458 
459   FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess);
460   FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, MetricsServiceObserver);
461   FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
462                            PermutedEntropyCacheClearedWhenLowEntropyReset);
463   FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
464 
465   DISALLOW_COPY_AND_ASSIGN(MetricsService);
466 };
467 
468 #endif  // COMPONENTS_METRICS_METRICS_SERVICE_H_
469