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