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