Home | History | Annotate | Download | only in metrics
      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 
     35 class MetricsReportingScheduler;
     36 class PrefService;
     37 class PrefRegistrySimple;
     38 class Profile;
     39 class TemplateURLService;
     40 
     41 namespace base {
     42 class DictionaryValue;
     43 class MessageLoopProxy;
     44 }
     45 
     46 namespace content {
     47 class RenderProcessHost;
     48 class WebContents;
     49 struct WebPluginInfo;
     50 }
     51 
     52 namespace extensions {
     53 class ExtensionDownloader;
     54 class ManifestFetchData;
     55 }
     56 
     57 namespace net {
     58 class URLFetcher;
     59 }
     60 
     61 namespace prerender {
     62 bool IsOmniboxEnabled(Profile* profile);
     63 }
     64 
     65 namespace tracked_objects {
     66 struct ProcessDataSnapshot;
     67 }
     68 
     69 class 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.
    501 class 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