1// Copyright (c) 2012 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 CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
9#define CHROME_BROWSER_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/weak_ptr.h"
19#include "base/metrics/field_trial.h"
20#include "base/process/kill.h"
21#include "chrome/browser/metrics/metrics_log.h"
22#include "chrome/browser/metrics/tracking_synchronizer_observer.h"
23#include "chrome/common/metrics/metrics_service_base.h"
24#include "chrome/installer/util/google_update_settings.h"
25#include "content/public/browser/browser_child_process_observer.h"
26#include "content/public/browser/notification_observer.h"
27#include "content/public/browser/notification_registrar.h"
28#include "content/public/browser/user_metrics.h"
29#include "net/url_request/url_fetcher_delegate.h"
30
31#if defined(OS_CHROMEOS)
32#include "chrome/browser/chromeos/external_metrics.h"
33#endif
34
35class MetricsReportingScheduler;
36class PrefService;
37class PrefRegistrySimple;
38class Profile;
39class TemplateURLService;
40
41namespace base {
42class DictionaryValue;
43class MessageLoopProxy;
44}
45
46namespace content {
47class RenderProcessHost;
48class WebContents;
49struct WebPluginInfo;
50}
51
52namespace extensions {
53class ExtensionDownloader;
54class ManifestFetchData;
55}
56
57namespace net {
58class URLFetcher;
59}
60
61namespace prerender {
62bool IsOmniboxEnabled(Profile* profile);
63}
64
65namespace tracked_objects {
66struct ProcessDataSnapshot;
67}
68
69class MetricsService
70    : public chrome_browser_metrics::TrackingSynchronizerObserver,
71      public content::BrowserChildProcessObserver,
72      public content::NotificationObserver,
73      public net::URLFetcherDelegate,
74      public MetricsServiceBase {
75 public:
76  MetricsService();
77  virtual ~MetricsService();
78
79  // Starts the metrics system, turning on recording and uploading of metrics.
80  // Should be called when starting up with metrics enabled, or when metrics
81  // are turned on.
82  void Start();
83
84  // Starts the metrics system in a special test-only mode. Metrics won't ever
85  // be uploaded or persisted in this mode, but metrics will be recorded in
86  // memory.
87  void StartRecordingForTests();
88
89  // Shuts down the metrics system. Should be called at shutdown, or if metrics
90  // are turned off.
91  void Stop();
92
93  // Enable/disable transmission of accumulated logs and crash reports (dumps).
94  // Calling Start() automatically enables reporting, but sending is
95  // asyncronous so this can be called immediately after Start() to prevent
96  // any uploading.
97  void EnableReporting();
98  void DisableReporting();
99
100  // Returns the client ID for this client, or the empty string if metrics
101  // recording is not currently running.
102  std::string GetClientId();
103
104  // Returns the preferred entropy provider used to seed persistent activities
105  // based on whether or not metrics reporting will be permitted on this client.
106  // The caller must determine if metrics reporting will be enabled for this
107  // client and pass that state in as |reporting_will_be_enabled|.
108  //
109  // If |reporting_will_be_enabled| is true, this method returns an entropy
110  // provider that has a high source of entropy, partially based on the client
111  // ID. Otherwise, an entropy provider that is based on a low entropy source
112  // is returned.
113  //
114  // Note that this reporting state can not be checked by reporting_active()
115  // because this method may need to be called before the MetricsService needs
116  // to be started.
117  scoped_ptr<const base::FieldTrial::EntropyProvider> CreateEntropyProvider(
118      bool reporting_will_be_enabled);
119
120  // Force the client ID to be generated. This is useful in case it's needed
121  // before recording.
122  void ForceClientIdCreation();
123
124  // At startup, prefs needs to be called with a list of all the pref names and
125  // types we'll be using.
126  static void RegisterPrefs(PrefRegistrySimple* registry);
127
128  // Set up notifications which indicate that a user is performing work. This is
129  // useful to allow some features to sleep, until the machine becomes active,
130  // such as precluding UMA uploads unless there was recent activity.
131  static void SetUpNotifications(content::NotificationRegistrar* registrar,
132                                 content::NotificationObserver* observer);
133
134  // Implementation of content::BrowserChildProcessObserver
135  virtual void BrowserChildProcessHostConnected(
136      const content::ChildProcessData& data) OVERRIDE;
137  virtual void BrowserChildProcessCrashed(
138      const content::ChildProcessData& data) OVERRIDE;
139  virtual void BrowserChildProcessInstanceCreated(
140      const content::ChildProcessData& data) OVERRIDE;
141
142  // Implementation of content::NotificationObserver
143  virtual void Observe(int type,
144                       const content::NotificationSource& source,
145                       const content::NotificationDetails& details) OVERRIDE;
146
147  // Invoked when we get a WM_SESSIONEND. This places a value in prefs that is
148  // reset when RecordCompletedSessionEnd is invoked.
149  void RecordStartOfSessionEnd();
150
151  // This should be called when the application is shutting down. It records
152  // that session end was successful.
153  void RecordCompletedSessionEnd();
154
155#if defined(OS_ANDROID) || defined(OS_IOS)
156  // Called when the application is going into background mode.
157  void OnAppEnterBackground();
158
159  // Called when the application is coming out of background mode.
160  void OnAppEnterForeground();
161#else
162  // Set the dirty flag, which will require a later call to LogCleanShutdown().
163  static void LogNeedForCleanShutdown();
164#endif  // defined(OS_ANDROID) || defined(OS_IOS)
165
166  // Saves in the preferences if the crash report registration was successful.
167  // This count is eventually send via UMA logs.
168  void RecordBreakpadRegistration(bool success);
169
170  // Saves in the preferences if the browser is running under a debugger.
171  // This count is eventually send via UMA logs.
172  void RecordBreakpadHasDebugger(bool has_debugger);
173
174  // Save any unsent logs into a persistent store in a pref.  We always do this
175  // at shutdown, but we can do it as we reduce the list as well.
176  void StoreUnsentLogs();
177
178#if defined(OS_CHROMEOS)
179  // Start the external metrics service, which collects metrics from Chrome OS
180  // and passes them to UMA.
181  void StartExternalMetrics();
182
183  // Records a Chrome OS crash.
184  void LogChromeOSCrash(const std::string &crash_type);
185#endif
186
187  bool recording_active() const;
188  bool reporting_active() const;
189
190  void LogPluginLoadingError(const base::FilePath& plugin_path);
191
192  // Redundant test to ensure that we are notified of a clean exit.
193  // This value should be true when process has completed shutdown.
194  static bool UmaMetricsProperlyShutdown();
195
196 private:
197  // The MetricsService has a lifecycle that is stored as a state.
198  // See metrics_service.cc for description of this lifecycle.
199  enum State {
200    INITIALIZED,            // Constructor was called.
201    INIT_TASK_SCHEDULED,    // Waiting for deferred init tasks to complete.
202    INIT_TASK_DONE,         // Waiting for timer to send initial log.
203    INITIAL_LOG_READY,      // Initial log generated, and waiting for reply.
204    SENDING_OLD_LOGS,       // Sending unsent logs from previous session.
205    SENDING_CURRENT_LOGS,   // Sending standard current logs as they acrue.
206  };
207
208  enum ShutdownCleanliness {
209    CLEANLY_SHUTDOWN = 0xdeadbeef,
210    NEED_TO_SHUTDOWN = ~CLEANLY_SHUTDOWN
211  };
212
213  // Designates which entropy source was returned from this MetricsService.
214  // This is used for testing to validate that we return the correct source
215  // depending on the state of the service.
216  enum EntropySourceReturned {
217    LAST_ENTROPY_NONE,
218    LAST_ENTROPY_LOW,
219    LAST_ENTROPY_HIGH,
220  };
221
222  struct ChildProcessStats;
223
224  // First part of the init task. Called on the FILE thread to load hardware
225  // class information.
226  static void InitTaskGetHardwareClass(base::WeakPtr<MetricsService> self,
227                                       base::MessageLoopProxy* target_loop);
228
229  // Callback from InitTaskGetHardwareClass() that continues the init task by
230  // loading plugin information.
231  void OnInitTaskGotHardwareClass(const std::string& hardware_class);
232
233  // Callback from PluginService::GetPlugins() that continues the init task by
234  // launching a task to gather Google Update statistics.
235  void OnInitTaskGotPluginInfo(
236      const std::vector<content::WebPluginInfo>& plugins);
237
238  // Task launched by OnInitTaskGotPluginInfo() that continues the init task by
239  // loading Google Update statistics.  Called on a blocking pool thread.
240  static void InitTaskGetGoogleUpdateData(base::WeakPtr<MetricsService> self,
241                                          base::MessageLoopProxy* target_loop);
242
243  // Callback from InitTaskGetGoogleUpdateData() that continues the init task by
244  // loading profiler data.
245  void OnInitTaskGotGoogleUpdateData(
246      const GoogleUpdateMetrics& google_update_metrics);
247
248  void OnUserAction(const std::string& action);
249
250  // TrackingSynchronizerObserver:
251  virtual void ReceivedProfilerData(
252      const tracked_objects::ProcessDataSnapshot& process_data,
253      int process_type) OVERRIDE;
254  // Callback that moves the state to INIT_TASK_DONE.
255  virtual void FinishedReceivingProfilerData() OVERRIDE;
256
257  // Returns the low entropy source for this client. This is a random value
258  // that is non-identifying amongst browser clients. This method will
259  // generate the entropy source value if it has not been called before.
260  int GetLowEntropySource();
261
262  // Returns the first entropy source that was returned by this service since
263  // start up, or NONE if neither was returned yet. This is exposed for testing
264  // only.
265  EntropySourceReturned entropy_source_returned() const {
266    return entropy_source_returned_;
267  }
268
269  // When we start a new version of Chromium (different from our last run), we
270  // need to discard the old crash stats so that we don't attribute crashes etc.
271  // in the old version to the current version (via current logs).
272  // Without this, a common reason to finally start a new version is to crash
273  // the old version (after an autoupdate has arrived), and so we'd bias
274  // initial results towards showing crashes :-(.
275  static void DiscardOldStabilityStats(PrefService* local_state);
276
277  // Turns recording on or off.
278  // DisableRecording() also forces a persistent save of logging state (if
279  // anything has been recorded, or transmitted).
280  void EnableRecording();
281  void DisableRecording();
282
283  // If in_idle is true, sets idle_since_last_transmission to true.
284  // If in_idle is false and idle_since_last_transmission_ is true, sets
285  // idle_since_last_transmission to false and starts the timer (provided
286  // starting the timer is permitted).
287  void HandleIdleSinceLastTransmission(bool in_idle);
288
289  // Set up client ID, session ID, etc.
290  void InitializeMetricsState();
291
292  // Generates a new client ID to use to identify self to metrics server.
293  static std::string GenerateClientID();
294
295  // Schedule the next save of LocalState information.  This is called
296  // automatically by the task that performs each save to schedule the next one.
297  void ScheduleNextStateSave();
298
299  // Save the LocalState information immediately. This should not be called by
300  // anybody other than the scheduler to avoid doing too many writes. When you
301  // make a change, call ScheduleNextStateSave() instead.
302  void SaveLocalState();
303
304  // Opens a new log for recording user experience metrics.
305  void OpenNewLog();
306
307  // Closes out the current log after adding any last information.
308  void CloseCurrentLog();
309
310  // Pushes the text of the current and staged logs into persistent storage.
311  // Called when Chrome shuts down.
312  void PushPendingLogsToPersistentStorage();
313
314  // Ensures that scheduler is running, assuming the current settings are such
315  // that metrics should be reported. If not, this is a no-op.
316  void StartSchedulerIfNecessary();
317
318  // Starts the process of uploading metrics data.
319  void StartScheduledUpload();
320
321  // Starts collecting any data that should be added to a log just before it is
322  // closed.
323  void StartFinalLogInfoCollection();
324  // Callbacks for various stages of final log info collection. Do not call
325  // these directly.
326  void OnMemoryDetailCollectionDone();
327  void OnHistogramSynchronizationDone();
328  void OnFinalLogInfoCollectionDone();
329
330  // Either closes the current log or creates and closes the initial log
331  // (depending on |state_|), and stages it for upload.
332  void StageNewLog();
333
334  // Record stats, client ID, Session ID, etc. in a special "first" log.
335  void PrepareInitialLog();
336
337  // Uploads the currently staged log (which must be non-null).
338  void SendStagedLog();
339
340  // Prepared the staged log to be passed to the server. Upon return,
341  // current_fetch_ should be reset with its upload data set to a compressed
342  // copy of the staged log.
343  void PrepareFetchWithStagedLog();
344
345  // Implementation of net::URLFetcherDelegate. Called after transmission
346  // completes (either successfully or with failure).
347  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
348
349  // Reads, increments and then sets the specified integer preference.
350  void IncrementPrefValue(const char* path);
351
352  // Reads, increments and then sets the specified long preference that is
353  // stored as a string.
354  void IncrementLongPrefsValue(const char* path);
355
356  // Records a renderer process crash.
357  void LogRendererCrash(content::RenderProcessHost* host,
358                        base::TerminationStatus status,
359                        int exit_code);
360
361  // Records a renderer process hang.
362  void LogRendererHang();
363
364  // Records that the browser was shut down cleanly.
365  void LogCleanShutdown();
366
367  // Returns reference to ChildProcessStats corresponding to |data|.
368  ChildProcessStats& GetChildProcessStats(
369      const content::ChildProcessData& data);
370
371  // Saves plugin-related updates from the in-object buffer to Local State
372  // for retrieval next time we send a Profile log (generally next launch).
373  void RecordPluginChanges(PrefService* pref);
374
375  // Records state that should be periodically saved, like uptime and
376  // buffered plugin stability statistics.
377  void RecordCurrentState(PrefService* pref);
378
379  // Logs the initiation of a page load and uses |web_contents| to do
380  // additional logging of the type of page loaded.
381  void LogLoadStarted(content::WebContents* web_contents);
382
383  // Checks whether a notification can be logged.
384  bool CanLogNotification();
385
386  // Sets the value of the specified path in prefs and schedules a save.
387  void RecordBooleanPrefValue(const char* path, bool value);
388
389  // Returns true if process of type |type| should be counted as a plugin
390  // process, and false otherwise.
391  static bool IsPluginProcess(int process_type);
392
393  content::ActionCallback action_callback_;
394
395  content::NotificationRegistrar registrar_;
396
397  // Indicate whether recording and reporting are currently happening.
398  // These should not be set directly, but by calling SetRecording and
399  // SetReporting.
400  bool recording_active_;
401  bool reporting_active_;
402
403  // Indicate whether test mode is enabled, where the initial log should never
404  // be cut, and logs are neither persisted nor uploaded.
405  bool test_mode_active_;
406
407  // The progession of states made by the browser are recorded in the following
408  // state.
409  State state_;
410
411  // Chrome OS hardware class (e.g., hardware qualification ID). This
412  // class identifies the configured system components such as CPU,
413  // WiFi adapter, etc.  For non Chrome OS hosts, this will be an
414  // empty string.
415  std::string hardware_class_;
416
417  // The list of plugins which was retrieved on the file thread.
418  std::vector<content::WebPluginInfo> plugins_;
419
420  // Google Update statistics, which were retrieved on a blocking pool thread.
421  GoogleUpdateMetrics google_update_metrics_;
422
423  // The initial log, used to record startup metrics.
424  scoped_ptr<MetricsLog> initial_log_;
425
426  // The outstanding transmission appears as a URL Fetch operation.
427  scoped_ptr<net::URLFetcher> current_fetch_;
428
429  // The TCP/UDP echo server to collect network connectivity stats.
430  std::string network_stats_server_;
431
432  // The HTTP pipelining test server.
433  std::string http_pipelining_test_server_;
434
435  // The identifier that's sent to the server with the log reports.
436  std::string client_id_;
437
438  // The non-identifying low entropy source value.
439  int low_entropy_source_;
440
441  // Whether the MetricsService object has received any notifications since
442  // the last time a transmission was sent.
443  bool idle_since_last_transmission_;
444
445  // A number that identifies the how many times the app has been launched.
446  int session_id_;
447
448  // Maps WebContentses (corresponding to tabs) or Browsers (corresponding to
449  // Windows) to a unique integer that we will use to identify them.
450  // |next_window_id_| is used to track which IDs we have used so far.
451  typedef std::map<uintptr_t, int> WindowMap;
452  WindowMap window_map_;
453  int next_window_id_;
454
455  // Buffer of child process notifications for quick access.
456  std::map<string16, ChildProcessStats> child_process_stats_buffer_;
457
458  // Weak pointers factory used to post task on different threads. All weak
459  // pointers managed by this factory have the same lifetime as MetricsService.
460  base::WeakPtrFactory<MetricsService> self_ptr_factory_;
461
462  // Weak pointers factory used for saving state. All weak pointers managed by
463  // this factory are invalidated in ScheduleNextStateSave.
464  base::WeakPtrFactory<MetricsService> state_saver_factory_;
465
466  // The scheduler for determining when uploads should happen.
467  scoped_ptr<MetricsReportingScheduler> scheduler_;
468
469  // Indicates that an asynchronous reporting step is running.
470  // This is used only for debugging.
471  bool waiting_for_asynchronous_reporting_step_;
472
473#if defined(OS_CHROMEOS)
474  // The external metric service is used to log ChromeOS UMA events.
475  scoped_refptr<chromeos::ExternalMetrics> external_metrics_;
476#endif
477
478  // The last entropy source returned by this service, used for testing.
479  EntropySourceReturned entropy_source_returned_;
480
481  // Reduntant marker to check that we completed our shutdown, and set the
482  // exited-cleanly bit in the prefs.
483  static ShutdownCleanliness clean_shutdown_status_;
484
485  FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, ClientIdCorrectlyFormatted);
486  FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess);
487  FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, LowEntropySource0NotReset);
488  FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
489                           PermutedEntropyCacheClearedWhenLowEntropyReset);
490  FRIEND_TEST_ALL_PREFIXES(MetricsServiceBrowserTest,
491                           CheckLowEntropySourceUsed);
492  FRIEND_TEST_ALL_PREFIXES(MetricsServiceReportingTest,
493                           CheckHighEntropySourceUsed);
494
495  DISALLOW_COPY_AND_ASSIGN(MetricsService);
496};
497
498// This class limits and documents access to the IsMetricsReportingEnabled()
499// method. Since the method is private, each user has to be explicitly declared
500// as a 'friend' below.
501class MetricsServiceHelper {
502 private:
503  friend bool prerender::IsOmniboxEnabled(Profile* profile);
504  friend class extensions::ExtensionDownloader;
505  friend class extensions::ManifestFetchData;
506
507  // Returns true if prefs::kMetricsReportingEnabled is set.
508  static bool IsMetricsReportingEnabled();
509
510  DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsServiceHelper);
511};
512
513#endif  // CHROME_BROWSER_METRICS_METRICS_SERVICE_H_
514