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 //------------------------------------------------------------------------------ 6 // Description of the life cycle of a instance of MetricsService. 7 // 8 // OVERVIEW 9 // 10 // A MetricsService instance is typically created at application startup. It is 11 // the central controller for the acquisition of log data, and the automatic 12 // transmission of that log data to an external server. Its major job is to 13 // manage logs, grouping them for transmission, and transmitting them. As part 14 // of its grouping, MS finalizes logs by including some just-in-time gathered 15 // memory statistics, snapshotting the current stats of numerous histograms, 16 // closing the logs, translating to protocol buffer format, and compressing the 17 // results for transmission. Transmission includes submitting a compressed log 18 // as data in a URL-post, and retransmitting (or retaining at process 19 // termination) if the attempted transmission failed. Retention across process 20 // terminations is done using the the PrefServices facilities. The retained logs 21 // (the ones that never got transmitted) are compressed and base64-encoded 22 // before being persisted. 23 // 24 // Logs fall into one of two categories: "initial logs," and "ongoing logs." 25 // There is at most one initial log sent for each complete run of the chromium 26 // product (from startup, to browser shutdown). An initial log is generally 27 // transmitted some short time (1 minute?) after startup, and includes stats 28 // such as recent crash info, the number and types of plugins, etc. The 29 // external server's response to the initial log conceptually tells this MS if 30 // it should continue transmitting logs (during this session). The server 31 // response can actually be much more detailed, and always includes (at a 32 // minimum) how often additional ongoing logs should be sent. 33 // 34 // After the above initial log, a series of ongoing logs will be transmitted. 35 // The first ongoing log actually begins to accumulate information stating when 36 // the MS was first constructed. Note that even though the initial log is 37 // commonly sent a full minute after startup, the initial log does not include 38 // much in the way of user stats. The most common interlog period (delay) 39 // is 30 minutes. That time period starts when the first user action causes a 40 // logging event. This means that if there is no user action, there may be long 41 // periods without any (ongoing) log transmissions. Ongoing logs typically 42 // contain very detailed records of user activities (ex: opened tab, closed 43 // tab, fetched URL, maximized window, etc.) In addition, just before an 44 // ongoing log is closed out, a call is made to gather memory statistics. Those 45 // memory statistics are deposited into a histogram, and the log finalization 46 // code is then called. In the finalization, a call to a Histogram server 47 // acquires a list of all local histograms that have been flagged for upload 48 // to the UMA server. The finalization also acquires a the most recent number 49 // of page loads, along with any counts of renderer or plugin crashes. 50 // 51 // When the browser shuts down, there will typically be a fragment of an ongoing 52 // log that has not yet been transmitted. At shutdown time, that fragment 53 // is closed (including snapshotting histograms), and persisted, for 54 // potential transmission during a future run of the product. 55 // 56 // There are two slightly abnormal shutdown conditions. There is a 57 // "disconnected scenario," and a "really fast startup and shutdown" scenario. 58 // In the "never connected" situation, the user has (during the running of the 59 // process) never established an internet connection. As a result, attempts to 60 // transmit the initial log have failed, and a lot(?) of data has accumulated in 61 // the ongoing log (which didn't yet get closed, because there was never even a 62 // contemplation of sending it). There is also a kindred "lost connection" 63 // situation, where a loss of connection prevented an ongoing log from being 64 // transmitted, and a (still open) log was stuck accumulating a lot(?) of data, 65 // while the earlier log retried its transmission. In both of these 66 // disconnected situations, two logs need to be, and are, persistently stored 67 // for future transmission. 68 // 69 // The other unusual shutdown condition, termed "really fast startup and 70 // shutdown," involves the deliberate user termination of the process before 71 // the initial log is even formed or transmitted. In that situation, no logging 72 // is done, but the historical crash statistics remain (unlogged) for inclusion 73 // in a future run's initial log. (i.e., we don't lose crash stats). 74 // 75 // With the above overview, we can now describe the state machine's various 76 // stats, based on the State enum specified in the state_ member. Those states 77 // are: 78 // 79 // INITIALIZED, // Constructor was called. 80 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. 81 // INIT_TASK_DONE, // Waiting for timer to send initial log. 82 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. 83 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. 84 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. 85 // 86 // In more detail, we have: 87 // 88 // INITIALIZED, // Constructor was called. 89 // The MS has been constructed, but has taken no actions to compose the 90 // initial log. 91 // 92 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to complete. 93 // Typically about 30 seconds after startup, a task is sent to a second thread 94 // (the file thread) to perform deferred (lower priority and slower) 95 // initialization steps such as getting the list of plugins. That task will 96 // (when complete) make an async callback (via a Task) to indicate the 97 // completion. 98 // 99 // INIT_TASK_DONE, // Waiting for timer to send initial log. 100 // The callback has arrived, and it is now possible for an initial log to be 101 // created. This callback typically arrives back less than one second after 102 // the deferred init task is dispatched. 103 // 104 // INITIAL_LOG_READY, // Initial log generated, and waiting for reply. 105 // This state is entered only after an initial log has been composed, and 106 // prepared for transmission. It is also the case that any previously unsent 107 // logs have been loaded into instance variables for possible transmission. 108 // 109 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. 110 // This state indicates that the initial log for this session has been 111 // successfully sent and it is now time to send any logs that were 112 // saved from previous sessions. All such logs will be transmitted before 113 // exiting this state, and proceeding with ongoing logs from the current session 114 // (see next state). 115 // 116 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. 117 // Current logs are being accumulated. Typically every 20 minutes a log is 118 // closed and finalized for transmission, at the same time as a new log is 119 // started. 120 // 121 // The progression through the above states is simple, and sequential, in the 122 // most common use cases. States proceed from INITIAL to SENDING_CURRENT_LOGS, 123 // and remain in the latter until shutdown. 124 // 125 // The one unusual case is when the user asks that we stop logging. When that 126 // happens, any staged (transmission in progress) log is persisted, and any log 127 // that is currently accumulating is also finalized and persisted. We then 128 // regress back to the SEND_OLD_LOGS state in case the user enables log 129 // recording again during this session. This way anything we have persisted 130 // will be sent automatically if/when we progress back to SENDING_CURRENT_LOG 131 // state. 132 // 133 // Another similar case is on mobile, when the application is backgrounded and 134 // then foregrounded again. Backgrounding created new "old" stored logs, so the 135 // state drops back from SENDING_CURRENT_LOGS to SENDING_OLD_LOGS so those logs 136 // will be sent. 137 // 138 // Also note that whenever we successfully send an old log, we mirror the list 139 // of logs into the PrefService. This ensures that IF we crash, we won't start 140 // up and retransmit our old logs again. 141 // 142 // Due to race conditions, it is always possible that a log file could be sent 143 // twice. For example, if a log file is sent, but not yet acknowledged by 144 // the external server, and the user shuts down, then a copy of the log may be 145 // saved for re-transmission. These duplicates could be filtered out server 146 // side, but are not expected to be a significant problem. 147 // 148 // 149 //------------------------------------------------------------------------------ 150 151 #include "chrome/browser/metrics/metrics_service.h" 152 153 #include <algorithm> 154 155 #include "base/bind.h" 156 #include "base/callback.h" 157 #include "base/command_line.h" 158 #include "base/guid.h" 159 #include "base/md5.h" 160 #include "base/metrics/histogram.h" 161 #include "base/metrics/sparse_histogram.h" 162 #include "base/metrics/statistics_recorder.h" 163 #include "base/prefs/pref_registry_simple.h" 164 #include "base/prefs/pref_service.h" 165 #include "base/rand_util.h" 166 #include "base/strings/string_number_conversions.h" 167 #include "base/strings/utf_string_conversions.h" 168 #include "base/threading/platform_thread.h" 169 #include "base/threading/thread.h" 170 #include "base/threading/thread_restrictions.h" 171 #include "base/tracked_objects.h" 172 #include "base/values.h" 173 #include "chrome/browser/browser_process.h" 174 #include "chrome/browser/chrome_notification_types.h" 175 #include "chrome/browser/extensions/extension_service.h" 176 #include "chrome/browser/extensions/process_map.h" 177 #include "chrome/browser/io_thread.h" 178 #include "chrome/browser/memory_details.h" 179 #include "chrome/browser/metrics/compression_utils.h" 180 #include "chrome/browser/metrics/gzipped_protobufs_field_trial.h" 181 #include "chrome/browser/metrics/metrics_log.h" 182 #include "chrome/browser/metrics/metrics_log_serializer.h" 183 #include "chrome/browser/metrics/metrics_reporting_scheduler.h" 184 #include "chrome/browser/metrics/time_ticks_experiment_win.h" 185 #include "chrome/browser/metrics/tracking_synchronizer.h" 186 #include "chrome/browser/net/http_pipelining_compatibility_client.h" 187 #include "chrome/browser/net/network_stats.h" 188 #include "chrome/browser/omnibox/omnibox_log.h" 189 #include "chrome/browser/prefs/scoped_user_pref_update.h" 190 #include "chrome/browser/profiles/profile.h" 191 #include "chrome/browser/ui/browser_list.h" 192 #include "chrome/browser/ui/browser_otr_state.h" 193 #include "chrome/browser/ui/search/search_tab_helper.h" 194 #include "chrome/common/child_process_logging.h" 195 #include "chrome/common/chrome_result_codes.h" 196 #include "chrome/common/chrome_switches.h" 197 #include "chrome/common/metrics/caching_permuted_entropy_provider.h" 198 #include "chrome/common/metrics/entropy_provider.h" 199 #include "chrome/common/metrics/metrics_log_manager.h" 200 #include "chrome/common/net/test_server_locations.h" 201 #include "chrome/common/pref_names.h" 202 #include "chrome/common/render_messages.h" 203 #include "content/public/browser/child_process_data.h" 204 #include "content/public/browser/histogram_fetcher.h" 205 #include "content/public/browser/load_notification_details.h" 206 #include "content/public/browser/notification_service.h" 207 #include "content/public/browser/plugin_service.h" 208 #include "content/public/browser/render_process_host.h" 209 #include "content/public/browser/user_metrics.h" 210 #include "content/public/browser/web_contents.h" 211 #include "content/public/common/process_type.h" 212 #include "content/public/common/webplugininfo.h" 213 #include "net/base/load_flags.h" 214 #include "net/url_request/url_fetcher.h" 215 216 // TODO(port): port browser_distribution.h. 217 #if !defined(OS_POSIX) 218 #include "chrome/installer/util/browser_distribution.h" 219 #endif 220 221 #if defined(OS_CHROMEOS) 222 #include "chrome/browser/chromeos/external_metrics.h" 223 #include "chrome/browser/chromeos/system/statistics_provider.h" 224 #endif 225 226 #if defined(OS_WIN) 227 #include <windows.h> // Needed for STATUS_* codes 228 #endif 229 230 using base::Time; 231 using content::BrowserThread; 232 using content::ChildProcessData; 233 using content::LoadNotificationDetails; 234 using content::PluginService; 235 236 namespace { 237 238 // Check to see that we're being called on only one thread. 239 bool IsSingleThreaded() { 240 static base::PlatformThreadId thread_id = 0; 241 if (!thread_id) 242 thread_id = base::PlatformThread::CurrentId(); 243 return base::PlatformThread::CurrentId() == thread_id; 244 } 245 246 // The delay, in seconds, after starting recording before doing expensive 247 // initialization work. 248 #if defined(OS_ANDROID) || defined(OS_IOS) 249 // On mobile devices, a significant portion of sessions last less than a minute. 250 // Use a shorter timer on these platforms to avoid losing data. 251 // TODO(dfalcantara): To avoid delaying startup, tighten up initialization so 252 // that it occurs after the user gets their initial page. 253 const int kInitializationDelaySeconds = 5; 254 #else 255 const int kInitializationDelaySeconds = 30; 256 #endif 257 258 // This specifies the amount of time to wait for all renderers to send their 259 // data. 260 const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds. 261 262 // The maximum number of events in a log uploaded to the UMA server. 263 const int kEventLimit = 2400; 264 265 // If an upload fails, and the transmission was over this byte count, then we 266 // will discard the log, and not try to retransmit it. We also don't persist 267 // the log to the prefs for transmission during the next chrome session if this 268 // limit is exceeded. 269 const size_t kUploadLogAvoidRetransmitSize = 50000; 270 271 // Interval, in minutes, between state saves. 272 const int kSaveStateIntervalMinutes = 5; 273 274 enum ResponseStatus { 275 UNKNOWN_FAILURE, 276 SUCCESS, 277 BAD_REQUEST, // Invalid syntax or log too large. 278 NO_RESPONSE, 279 NUM_RESPONSE_STATUSES 280 }; 281 282 ResponseStatus ResponseCodeToStatus(int response_code) { 283 switch (response_code) { 284 case 200: 285 return SUCCESS; 286 case 400: 287 return BAD_REQUEST; 288 case net::URLFetcher::RESPONSE_CODE_INVALID: 289 return NO_RESPONSE; 290 default: 291 return UNKNOWN_FAILURE; 292 } 293 } 294 295 // The argument used to generate a non-identifying entropy source. We want no 296 // more than 13 bits of entropy, so use this max to return a number in the range 297 // [0, 7999] as the entropy source (12.97 bits of entropy). 298 const int kMaxLowEntropySize = 8000; 299 300 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that the 301 // value has not yet been set. 302 const int kLowEntropySourceNotSet = -1; 303 304 // Generates a new non-identifying entropy source used to seed persistent 305 // activities. 306 int GenerateLowEntropySource() { 307 return base::RandInt(0, kMaxLowEntropySize - 1); 308 } 309 310 // Converts an exit code into something that can be inserted into our 311 // histograms (which expect non-negative numbers less than MAX_INT). 312 int MapCrashExitCodeForHistogram(int exit_code) { 313 #if defined(OS_WIN) 314 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in 315 // histograms.cc. Solve this by remapping it to a smaller value, which 316 // hopefully doesn't conflict with other codes. 317 if (exit_code == STATUS_GUARD_PAGE_VIOLATION) 318 return 0x1FCF7EC3; // Randomly picked number. 319 #endif 320 321 return std::abs(exit_code); 322 } 323 324 void MarkAppCleanShutdownAndCommit() { 325 PrefService* pref = g_browser_process->local_state(); 326 pref->SetBoolean(prefs::kStabilityExitedCleanly, true); 327 // Start writing right away (write happens on a different thread). 328 pref->CommitPendingWrite(); 329 } 330 331 } // namespace 332 333 // static 334 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ = 335 MetricsService::CLEANLY_SHUTDOWN; 336 337 // This is used to quickly log stats from child process related notifications in 338 // MetricsService::child_stats_buffer_. The buffer's contents are transferred 339 // out when Local State is periodically saved. The information is then 340 // reported to the UMA server on next launch. 341 struct MetricsService::ChildProcessStats { 342 public: 343 explicit ChildProcessStats(int process_type) 344 : process_launches(0), 345 process_crashes(0), 346 instances(0), 347 loading_errors(0), 348 process_type(process_type) {} 349 350 // This constructor is only used by the map to return some default value for 351 // an index for which no value has been assigned. 352 ChildProcessStats() 353 : process_launches(0), 354 process_crashes(0), 355 instances(0), 356 loading_errors(0), 357 process_type(content::PROCESS_TYPE_UNKNOWN) {} 358 359 // The number of times that the given child process has been launched 360 int process_launches; 361 362 // The number of times that the given child process has crashed 363 int process_crashes; 364 365 // The number of instances of this child process that have been created. 366 // An instance is a DOM object rendered by this child process during a page 367 // load. 368 int instances; 369 370 // The number of times there was an error loading an instance of this child 371 // process. 372 int loading_errors; 373 374 int process_type; 375 }; 376 377 // Handles asynchronous fetching of memory details. 378 // Will run the provided task after finished. 379 class MetricsMemoryDetails : public MemoryDetails { 380 public: 381 explicit MetricsMemoryDetails(const base::Closure& callback) 382 : callback_(callback) {} 383 384 virtual void OnDetailsAvailable() OVERRIDE { 385 base::MessageLoop::current()->PostTask(FROM_HERE, callback_); 386 } 387 388 private: 389 virtual ~MetricsMemoryDetails() {} 390 391 base::Closure callback_; 392 DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails); 393 }; 394 395 // static 396 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) { 397 DCHECK(IsSingleThreaded()); 398 registry->RegisterStringPref(prefs::kMetricsClientID, std::string()); 399 registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource, 400 kLowEntropySourceNotSet); 401 registry->RegisterInt64Pref(prefs::kMetricsClientIDTimestamp, 0); 402 registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0); 403 registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0); 404 registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string()); 405 registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0); 406 registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true); 407 registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true); 408 registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1); 409 registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0); 410 registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0); 411 registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0); 412 registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0); 413 registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0); 414 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount, 415 0); 416 registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0); 417 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0); 418 registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0); 419 registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess, 420 0); 421 registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0); 422 registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0); 423 #if defined(OS_CHROMEOS) 424 registry->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0); 425 registry->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0); 426 registry->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount, 0); 427 #endif // OS_CHROMEOS 428 429 registry->RegisterListPref(prefs::kMetricsInitialLogs); 430 registry->RegisterListPref(prefs::kMetricsOngoingLogs); 431 432 registry->RegisterInt64Pref(prefs::kInstallDate, 0); 433 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0); 434 registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0); 435 registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0); 436 registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0); 437 registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0); 438 } 439 440 // static 441 void MetricsService::DiscardOldStabilityStats(PrefService* local_state) { 442 local_state->SetBoolean(prefs::kStabilityExitedCleanly, true); 443 local_state->SetBoolean(prefs::kStabilitySessionEndCompleted, true); 444 445 local_state->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0); 446 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0); 447 local_state->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0); 448 local_state->SetInteger(prefs::kStabilityDebuggerPresent, 0); 449 local_state->SetInteger(prefs::kStabilityDebuggerNotPresent, 0); 450 451 local_state->SetInteger(prefs::kStabilityLaunchCount, 0); 452 local_state->SetInteger(prefs::kStabilityCrashCount, 0); 453 454 local_state->SetInteger(prefs::kStabilityPageLoadCount, 0); 455 local_state->SetInteger(prefs::kStabilityRendererCrashCount, 0); 456 local_state->SetInteger(prefs::kStabilityRendererHangCount, 0); 457 458 local_state->SetInt64(prefs::kStabilityLaunchTimeSec, 0); 459 local_state->SetInt64(prefs::kStabilityLastTimestampSec, 0); 460 461 local_state->ClearPref(prefs::kStabilityPluginStats); 462 463 local_state->ClearPref(prefs::kMetricsInitialLogs); 464 local_state->ClearPref(prefs::kMetricsOngoingLogs); 465 } 466 467 MetricsService::MetricsService() 468 : recording_active_(false), 469 reporting_active_(false), 470 test_mode_active_(false), 471 state_(INITIALIZED), 472 low_entropy_source_(kLowEntropySourceNotSet), 473 idle_since_last_transmission_(false), 474 next_window_id_(0), 475 self_ptr_factory_(this), 476 state_saver_factory_(this), 477 waiting_for_asynchronous_reporting_step_(false), 478 entropy_source_returned_(LAST_ENTROPY_NONE) { 479 DCHECK(IsSingleThreaded()); 480 InitializeMetricsState(); 481 482 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload, 483 self_ptr_factory_.GetWeakPtr()); 484 scheduler_.reset(new MetricsReportingScheduler(callback)); 485 log_manager_.set_log_serializer(new MetricsLogSerializer()); 486 log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize); 487 488 BrowserChildProcessObserver::Add(this); 489 } 490 491 MetricsService::~MetricsService() { 492 DisableRecording(); 493 494 BrowserChildProcessObserver::Remove(this); 495 } 496 497 void MetricsService::Start() { 498 HandleIdleSinceLastTransmission(false); 499 EnableRecording(); 500 EnableReporting(); 501 } 502 503 void MetricsService::StartRecordingForTests() { 504 test_mode_active_ = true; 505 EnableRecording(); 506 DisableReporting(); 507 } 508 509 void MetricsService::Stop() { 510 HandleIdleSinceLastTransmission(false); 511 DisableReporting(); 512 DisableRecording(); 513 } 514 515 void MetricsService::EnableReporting() { 516 if (reporting_active_) 517 return; 518 reporting_active_ = true; 519 StartSchedulerIfNecessary(); 520 } 521 522 void MetricsService::DisableReporting() { 523 reporting_active_ = false; 524 } 525 526 std::string MetricsService::GetClientId() { 527 return client_id_; 528 } 529 530 scoped_ptr<const base::FieldTrial::EntropyProvider> 531 MetricsService::CreateEntropyProvider(bool reporting_will_be_enabled) { 532 // For metrics reporting-enabled users, we combine the client ID and low 533 // entropy source to get the final entropy source. Otherwise, only use the low 534 // entropy source. 535 // This has two useful properties: 536 // 1) It makes the entropy source less identifiable for parties that do not 537 // know the low entropy source. 538 // 2) It makes the final entropy source resettable. 539 const int low_entropy_source_value = GetLowEntropySource(); 540 UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue", 541 low_entropy_source_value); 542 if (reporting_will_be_enabled) { 543 if (entropy_source_returned_ == LAST_ENTROPY_NONE) 544 entropy_source_returned_ = LAST_ENTROPY_HIGH; 545 DCHECK_EQ(LAST_ENTROPY_HIGH, entropy_source_returned_); 546 const std::string high_entropy_source = 547 client_id_ + base::IntToString(low_entropy_source_value); 548 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 549 new metrics::SHA1EntropyProvider(high_entropy_source)); 550 } 551 552 if (entropy_source_returned_ == LAST_ENTROPY_NONE) 553 entropy_source_returned_ = LAST_ENTROPY_LOW; 554 DCHECK_EQ(LAST_ENTROPY_LOW, entropy_source_returned_); 555 556 #if defined(OS_ANDROID) || defined(OS_IOS) 557 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 558 new metrics::CachingPermutedEntropyProvider( 559 g_browser_process->local_state(), 560 low_entropy_source_value, 561 kMaxLowEntropySize)); 562 #else 563 return scoped_ptr<const base::FieldTrial::EntropyProvider>( 564 new metrics::PermutedEntropyProvider(low_entropy_source_value, 565 kMaxLowEntropySize)); 566 #endif 567 } 568 569 void MetricsService::ForceClientIdCreation() { 570 if (!client_id_.empty()) 571 return; 572 PrefService* pref = g_browser_process->local_state(); 573 client_id_ = pref->GetString(prefs::kMetricsClientID); 574 if (!client_id_.empty()) 575 return; 576 577 client_id_ = GenerateClientID(); 578 pref->SetString(prefs::kMetricsClientID, client_id_); 579 580 // Might as well make a note of how long this ID has existed 581 pref->SetString(prefs::kMetricsClientIDTimestamp, 582 base::Int64ToString(Time::Now().ToTimeT())); 583 } 584 585 void MetricsService::EnableRecording() { 586 DCHECK(IsSingleThreaded()); 587 588 if (recording_active_) 589 return; 590 recording_active_ = true; 591 592 ForceClientIdCreation(); 593 child_process_logging::SetClientId(client_id_); 594 if (!log_manager_.current_log()) 595 OpenNewLog(); 596 597 SetUpNotifications(®istrar_, this); 598 content::RemoveActionCallback(action_callback_); 599 action_callback_ = base::Bind(&MetricsService::OnUserAction, 600 base::Unretained(this)); 601 content::AddActionCallback(action_callback_); 602 } 603 604 void MetricsService::DisableRecording() { 605 DCHECK(IsSingleThreaded()); 606 607 if (!recording_active_) 608 return; 609 recording_active_ = false; 610 611 content::RemoveActionCallback(action_callback_); 612 registrar_.RemoveAll(); 613 PushPendingLogsToPersistentStorage(); 614 DCHECK(!log_manager_.has_staged_log()); 615 } 616 617 bool MetricsService::recording_active() const { 618 DCHECK(IsSingleThreaded()); 619 return recording_active_; 620 } 621 622 bool MetricsService::reporting_active() const { 623 DCHECK(IsSingleThreaded()); 624 return reporting_active_; 625 } 626 627 // static 628 void MetricsService::SetUpNotifications( 629 content::NotificationRegistrar* registrar, 630 content::NotificationObserver* observer) { 631 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED, 632 content::NotificationService::AllBrowserContextsAndSources()); 633 registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED, 634 content::NotificationService::AllSources()); 635 registrar->Add(observer, chrome::NOTIFICATION_TAB_PARENTED, 636 content::NotificationService::AllSources()); 637 registrar->Add(observer, chrome::NOTIFICATION_TAB_CLOSING, 638 content::NotificationService::AllSources()); 639 registrar->Add(observer, content::NOTIFICATION_LOAD_START, 640 content::NotificationService::AllSources()); 641 registrar->Add(observer, content::NOTIFICATION_LOAD_STOP, 642 content::NotificationService::AllSources()); 643 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 644 content::NotificationService::AllSources()); 645 registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_HANG, 646 content::NotificationService::AllSources()); 647 registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, 648 content::NotificationService::AllSources()); 649 } 650 651 void MetricsService::BrowserChildProcessHostConnected( 652 const content::ChildProcessData& data) { 653 GetChildProcessStats(data).process_launches++; 654 } 655 656 void MetricsService::BrowserChildProcessCrashed( 657 const content::ChildProcessData& data) { 658 GetChildProcessStats(data).process_crashes++; 659 // Exclude plugin crashes from the count below because we report them via 660 // a separate UMA metric. 661 if (!IsPluginProcess(data.process_type)) 662 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); 663 } 664 665 void MetricsService::BrowserChildProcessInstanceCreated( 666 const content::ChildProcessData& data) { 667 GetChildProcessStats(data).instances++; 668 } 669 670 void MetricsService::Observe(int type, 671 const content::NotificationSource& source, 672 const content::NotificationDetails& details) { 673 DCHECK(log_manager_.current_log()); 674 DCHECK(IsSingleThreaded()); 675 676 if (!CanLogNotification()) 677 return; 678 679 switch (type) { 680 case chrome::NOTIFICATION_BROWSER_OPENED: 681 case chrome::NOTIFICATION_BROWSER_CLOSED: 682 case chrome::NOTIFICATION_TAB_PARENTED: 683 case chrome::NOTIFICATION_TAB_CLOSING: 684 case content::NOTIFICATION_LOAD_STOP: 685 // These notifications are currently used only to break out of idle mode. 686 break; 687 688 case content::NOTIFICATION_LOAD_START: { 689 content::NavigationController* controller = 690 content::Source<content::NavigationController>(source).ptr(); 691 content::WebContents* web_contents = controller->GetWebContents(); 692 LogLoadStarted(web_contents); 693 break; 694 } 695 696 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 697 content::RenderProcessHost::RendererClosedDetails* process_details = 698 content::Details< 699 content::RenderProcessHost::RendererClosedDetails>( 700 details).ptr(); 701 content::RenderProcessHost* host = 702 content::Source<content::RenderProcessHost>(source).ptr(); 703 LogRendererCrash( 704 host, process_details->status, process_details->exit_code); 705 } 706 break; 707 708 case content::NOTIFICATION_RENDERER_PROCESS_HANG: 709 LogRendererHang(); 710 break; 711 712 case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: { 713 MetricsLog* current_log = 714 static_cast<MetricsLog*>(log_manager_.current_log()); 715 DCHECK(current_log); 716 current_log->RecordOmniboxOpenedURL( 717 *content::Details<OmniboxLog>(details).ptr()); 718 break; 719 } 720 721 default: 722 NOTREACHED(); 723 break; 724 } 725 726 HandleIdleSinceLastTransmission(false); 727 } 728 729 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) { 730 // If there wasn't a lot of action, maybe the computer was asleep, in which 731 // case, the log transmissions should have stopped. Here we start them up 732 // again. 733 if (!in_idle && idle_since_last_transmission_) 734 StartSchedulerIfNecessary(); 735 idle_since_last_transmission_ = in_idle; 736 } 737 738 void MetricsService::RecordStartOfSessionEnd() { 739 LogCleanShutdown(); 740 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false); 741 } 742 743 void MetricsService::RecordCompletedSessionEnd() { 744 LogCleanShutdown(); 745 RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true); 746 } 747 748 #if defined(OS_ANDROID) || defined(OS_IOS) 749 void MetricsService::OnAppEnterBackground() { 750 scheduler_->Stop(); 751 752 MarkAppCleanShutdownAndCommit(); 753 754 // At this point, there's no way of knowing when the process will be 755 // killed, so this has to be treated similar to a shutdown, closing and 756 // persisting all logs. Unlinke a shutdown, the state is primed to be ready 757 // to continue logging and uploading if the process does return. 758 if (recording_active() && state_ >= INITIAL_LOG_READY) { 759 PushPendingLogsToPersistentStorage(); 760 // Persisting logs closes the current log, so start recording a new log 761 // immediately to capture any background work that might be done before the 762 // process is killed. 763 OpenNewLog(); 764 } 765 } 766 767 void MetricsService::OnAppEnterForeground() { 768 PrefService* pref = g_browser_process->local_state(); 769 pref->SetBoolean(prefs::kStabilityExitedCleanly, false); 770 771 StartSchedulerIfNecessary(); 772 } 773 #else 774 void MetricsService::LogNeedForCleanShutdown() { 775 PrefService* pref = g_browser_process->local_state(); 776 pref->SetBoolean(prefs::kStabilityExitedCleanly, false); 777 // Redundant setting to be sure we call for a clean shutdown. 778 clean_shutdown_status_ = NEED_TO_SHUTDOWN; 779 } 780 #endif // defined(OS_ANDROID) || defined(OS_IOS) 781 782 void MetricsService::RecordBreakpadRegistration(bool success) { 783 if (!success) 784 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail); 785 else 786 IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess); 787 } 788 789 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) { 790 if (!has_debugger) 791 IncrementPrefValue(prefs::kStabilityDebuggerNotPresent); 792 else 793 IncrementPrefValue(prefs::kStabilityDebuggerPresent); 794 } 795 796 //------------------------------------------------------------------------------ 797 // private methods 798 //------------------------------------------------------------------------------ 799 800 801 //------------------------------------------------------------------------------ 802 // Initialization methods 803 804 void MetricsService::InitializeMetricsState() { 805 #if defined(OS_POSIX) 806 network_stats_server_ = chrome_common_net::kEchoTestServerLocation; 807 http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl; 808 #else 809 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 810 network_stats_server_ = dist->GetNetworkStatsServer(); 811 http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer(); 812 #endif 813 814 PrefService* pref = g_browser_process->local_state(); 815 DCHECK(pref); 816 817 if ((pref->GetInt64(prefs::kStabilityStatsBuildTime) 818 != MetricsLog::GetBuildTime()) || 819 (pref->GetString(prefs::kStabilityStatsVersion) 820 != MetricsLog::GetVersionString())) { 821 // This is a new version, so we don't want to confuse the stats about the 822 // old version with info that we upload. 823 DiscardOldStabilityStats(pref); 824 pref->SetString(prefs::kStabilityStatsVersion, 825 MetricsLog::GetVersionString()); 826 pref->SetInt64(prefs::kStabilityStatsBuildTime, 827 MetricsLog::GetBuildTime()); 828 } 829 830 // Update session ID 831 session_id_ = pref->GetInteger(prefs::kMetricsSessionID); 832 ++session_id_; 833 pref->SetInteger(prefs::kMetricsSessionID, session_id_); 834 835 // Stability bookkeeping 836 IncrementPrefValue(prefs::kStabilityLaunchCount); 837 838 if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) { 839 IncrementPrefValue(prefs::kStabilityCrashCount); 840 // Reset flag, and wait until we call LogNeedForCleanShutdown() before 841 // monitoring. 842 pref->SetBoolean(prefs::kStabilityExitedCleanly, true); 843 } 844 845 if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) { 846 IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount); 847 // This is marked false when we get a WM_ENDSESSION. 848 pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true); 849 } 850 851 // Initialize uptime counters. 852 int64 startup_uptime = MetricsLog::GetIncrementalUptime(pref); 853 DCHECK_EQ(0, startup_uptime); 854 // For backwards compatibility, leave this intact in case Omaha is checking 855 // them. prefs::kStabilityLastTimestampSec may also be useless now. 856 // TODO(jar): Delete these if they have no uses. 857 pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT()); 858 859 // Bookkeeping for the uninstall metrics. 860 IncrementLongPrefsValue(prefs::kUninstallLaunchCount); 861 862 // Get stats on use of command line. 863 const CommandLine* command_line(CommandLine::ForCurrentProcess()); 864 size_t common_commands = 0; 865 if (command_line->HasSwitch(switches::kUserDataDir)) { 866 ++common_commands; 867 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1); 868 } 869 870 if (command_line->HasSwitch(switches::kApp)) { 871 ++common_commands; 872 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1); 873 } 874 875 size_t switch_count = command_line->GetSwitches().size(); 876 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count); 877 UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount", 878 switch_count - common_commands); 879 880 // Kick off the process of saving the state (so the uptime numbers keep 881 // getting updated) every n minutes. 882 ScheduleNextStateSave(); 883 } 884 885 // static 886 void MetricsService::InitTaskGetHardwareClass( 887 base::WeakPtr<MetricsService> self, 888 base::MessageLoopProxy* target_loop) { 889 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 890 891 std::string hardware_class; 892 #if defined(OS_CHROMEOS) 893 chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic( 894 "hardware_class", &hardware_class); 895 #endif // OS_CHROMEOS 896 897 target_loop->PostTask(FROM_HERE, 898 base::Bind(&MetricsService::OnInitTaskGotHardwareClass, 899 self, hardware_class)); 900 } 901 902 void MetricsService::OnInitTaskGotHardwareClass( 903 const std::string& hardware_class) { 904 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 905 hardware_class_ = hardware_class; 906 907 #if defined(ENABLE_PLUGINS) 908 // Start the next part of the init task: loading plugin information. 909 PluginService::GetInstance()->GetPlugins( 910 base::Bind(&MetricsService::OnInitTaskGotPluginInfo, 911 self_ptr_factory_.GetWeakPtr())); 912 #else 913 std::vector<content::WebPluginInfo> plugin_list_empty; 914 OnInitTaskGotPluginInfo(plugin_list_empty); 915 #endif // defined(ENABLE_PLUGINS) 916 } 917 918 void MetricsService::OnInitTaskGotPluginInfo( 919 const std::vector<content::WebPluginInfo>& plugins) { 920 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 921 plugins_ = plugins; 922 923 // Schedules a task on a blocking pool thread to gather Google Update 924 // statistics (requires Registry reads). 925 BrowserThread::PostBlockingPoolTask( 926 FROM_HERE, 927 base::Bind(&MetricsService::InitTaskGetGoogleUpdateData, 928 self_ptr_factory_.GetWeakPtr(), 929 base::MessageLoop::current()->message_loop_proxy())); 930 } 931 932 // static 933 void MetricsService::InitTaskGetGoogleUpdateData( 934 base::WeakPtr<MetricsService> self, 935 base::MessageLoopProxy* target_loop) { 936 GoogleUpdateMetrics google_update_metrics; 937 938 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) 939 const bool system_install = GoogleUpdateSettings::IsSystemInstall(); 940 941 google_update_metrics.is_system_install = system_install; 942 google_update_metrics.last_started_au = 943 GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install); 944 google_update_metrics.last_checked = 945 GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install); 946 GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate( 947 system_install, 948 &google_update_metrics.google_update_data); 949 GoogleUpdateSettings::GetUpdateDetail( 950 system_install, 951 &google_update_metrics.product_data); 952 #endif // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD) 953 954 target_loop->PostTask(FROM_HERE, 955 base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData, 956 self, google_update_metrics)); 957 } 958 959 void MetricsService::OnInitTaskGotGoogleUpdateData( 960 const GoogleUpdateMetrics& google_update_metrics) { 961 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 962 963 google_update_metrics_ = google_update_metrics; 964 965 // Start the next part of the init task: fetching performance data. This will 966 // call into |FinishedReceivingProfilerData()| when the task completes. 967 chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously( 968 self_ptr_factory_.GetWeakPtr()); 969 } 970 971 void MetricsService::OnUserAction(const std::string& action) { 972 if (!CanLogNotification()) 973 return; 974 975 log_manager_.current_log()->RecordUserAction(action.c_str()); 976 HandleIdleSinceLastTransmission(false); 977 } 978 979 void MetricsService::ReceivedProfilerData( 980 const tracked_objects::ProcessDataSnapshot& process_data, 981 int process_type) { 982 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 983 984 // Upon the first callback, create the initial log so that we can immediately 985 // save the profiler data. 986 if (!initial_log_.get()) 987 initial_log_.reset(new MetricsLog(client_id_, session_id_)); 988 989 initial_log_->RecordProfilerData(process_data, process_type); 990 } 991 992 void MetricsService::FinishedReceivingProfilerData() { 993 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 994 state_ = INIT_TASK_DONE; 995 } 996 997 int MetricsService::GetLowEntropySource() { 998 // Note that the default value for the low entropy source and the default pref 999 // value are both kLowEntropySourceNotSet, which is used to identify if the 1000 // value has been set or not. 1001 if (low_entropy_source_ != kLowEntropySourceNotSet) 1002 return low_entropy_source_; 1003 1004 PrefService* local_state = g_browser_process->local_state(); 1005 const CommandLine* command_line(CommandLine::ForCurrentProcess()); 1006 // Only try to load the value from prefs if the user did not request a reset. 1007 // Otherwise, skip to generating a new value. 1008 if (!command_line->HasSwitch(switches::kResetVariationState)) { 1009 int value = local_state->GetInteger(prefs::kMetricsLowEntropySource); 1010 // Old versions of the code would generate values in the range of [1, 8192], 1011 // before the range was switched to [0, 8191] and then to [0, 7999]. Map 1012 // 8192 to 0, so that the 0th bucket remains uniform, while re-generating 1013 // the low entropy source for old values in the [8000, 8191] range. 1014 if (value == 8192) 1015 value = 0; 1016 // If the value is outside the [0, kMaxLowEntropySize) range, re-generate 1017 // it below. 1018 if (value >= 0 && value < kMaxLowEntropySize) { 1019 low_entropy_source_ = value; 1020 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false); 1021 return low_entropy_source_; 1022 } 1023 } 1024 1025 UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true); 1026 low_entropy_source_ = GenerateLowEntropySource(); 1027 local_state->SetInteger(prefs::kMetricsLowEntropySource, low_entropy_source_); 1028 metrics::CachingPermutedEntropyProvider::ClearCache(local_state); 1029 1030 return low_entropy_source_; 1031 } 1032 1033 // static 1034 std::string MetricsService::GenerateClientID() { 1035 return base::GenerateGUID(); 1036 } 1037 1038 //------------------------------------------------------------------------------ 1039 // State save methods 1040 1041 void MetricsService::ScheduleNextStateSave() { 1042 state_saver_factory_.InvalidateWeakPtrs(); 1043 1044 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 1045 base::Bind(&MetricsService::SaveLocalState, 1046 state_saver_factory_.GetWeakPtr()), 1047 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes)); 1048 } 1049 1050 void MetricsService::SaveLocalState() { 1051 PrefService* pref = g_browser_process->local_state(); 1052 if (!pref) { 1053 NOTREACHED(); 1054 return; 1055 } 1056 1057 RecordCurrentState(pref); 1058 1059 // TODO(jar):110021 Does this run down the batteries???? 1060 ScheduleNextStateSave(); 1061 } 1062 1063 1064 //------------------------------------------------------------------------------ 1065 // Recording control methods 1066 1067 void MetricsService::OpenNewLog() { 1068 DCHECK(!log_manager_.current_log()); 1069 1070 log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_), 1071 MetricsLogManager::ONGOING_LOG); 1072 if (state_ == INITIALIZED) { 1073 // We only need to schedule that run once. 1074 state_ = INIT_TASK_SCHEDULED; 1075 1076 // Schedules a task on the file thread for execution of slower 1077 // initialization steps (such as plugin list generation) necessary 1078 // for sending the initial log. This avoids blocking the main UI 1079 // thread. 1080 BrowserThread::PostDelayedTask( 1081 BrowserThread::FILE, 1082 FROM_HERE, 1083 base::Bind(&MetricsService::InitTaskGetHardwareClass, 1084 self_ptr_factory_.GetWeakPtr(), 1085 base::MessageLoop::current()->message_loop_proxy()), 1086 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); 1087 } 1088 } 1089 1090 void MetricsService::CloseCurrentLog() { 1091 if (!log_manager_.current_log()) 1092 return; 1093 1094 // TODO(jar): Integrate bounds on log recording more consistently, so that we 1095 // can stop recording logs that are too big much sooner. 1096 if (log_manager_.current_log()->num_events() > kEventLimit) { 1097 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events", 1098 log_manager_.current_log()->num_events()); 1099 log_manager_.DiscardCurrentLog(); 1100 OpenNewLog(); // Start trivial log to hold our histograms. 1101 } 1102 1103 // Adds to ongoing logs. 1104 log_manager_.current_log()->set_hardware_class(hardware_class_); 1105 1106 // Put incremental data (histogram deltas, and realtime stats deltas) at the 1107 // end of all log transmissions (initial log handles this separately). 1108 // RecordIncrementalStabilityElements only exists on the derived 1109 // MetricsLog class. 1110 MetricsLog* current_log = 1111 static_cast<MetricsLog*>(log_manager_.current_log()); 1112 DCHECK(current_log); 1113 current_log->RecordEnvironmentProto(plugins_, google_update_metrics_); 1114 current_log->RecordIncrementalStabilityElements(plugins_); 1115 RecordCurrentHistograms(); 1116 1117 log_manager_.FinishCurrentLog(); 1118 } 1119 1120 void MetricsService::PushPendingLogsToPersistentStorage() { 1121 if (state_ < INITIAL_LOG_READY) 1122 return; // We didn't and still don't have time to get plugin list etc. 1123 1124 if (log_manager_.has_staged_log()) { 1125 // We may race here, and send second copy of the log later. 1126 MetricsLogManager::StoreType store_type; 1127 if (current_fetch_.get()) 1128 store_type = MetricsLogManager::PROVISIONAL_STORE; 1129 else 1130 store_type = MetricsLogManager::NORMAL_STORE; 1131 log_manager_.StoreStagedLogAsUnsent(store_type); 1132 } 1133 DCHECK(!log_manager_.has_staged_log()); 1134 CloseCurrentLog(); 1135 StoreUnsentLogs(); 1136 1137 // If there was a staged and/or current log, then there is now at least one 1138 // log waiting to be uploaded. 1139 if (log_manager_.has_unsent_logs()) 1140 state_ = SENDING_OLD_LOGS; 1141 } 1142 1143 //------------------------------------------------------------------------------ 1144 // Transmission of logs methods 1145 1146 void MetricsService::StartSchedulerIfNecessary() { 1147 // Never schedule cutting or uploading of logs in test mode. 1148 if (test_mode_active_) 1149 return; 1150 1151 // Even if reporting is disabled, the scheduler is needed to trigger the 1152 // creation of the initial log, which must be done in order for any logs to be 1153 // persisted on shutdown or backgrounding. 1154 if (recording_active() && (reporting_active() || state_ < INITIAL_LOG_READY)) 1155 scheduler_->Start(); 1156 } 1157 1158 void MetricsService::StartScheduledUpload() { 1159 // If we're getting no notifications, then the log won't have much in it, and 1160 // it's possible the computer is about to go to sleep, so don't upload and 1161 // stop the scheduler. 1162 // If recording has been turned off, the scheduler doesn't need to run. 1163 // If reporting is off, proceed if the initial log hasn't been created, since 1164 // that has to happen in order for logs to be cut and stored when persisting. 1165 // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or 1166 // recording are turned off instead of letting it fire and then aborting. 1167 if (idle_since_last_transmission_ || 1168 !recording_active() || 1169 (!reporting_active() && state_ >= INITIAL_LOG_READY)) { 1170 scheduler_->Stop(); 1171 scheduler_->UploadCancelled(); 1172 return; 1173 } 1174 1175 // If the callback was to upload an old log, but there no longer is one, 1176 // just report success back to the scheduler to begin the ongoing log 1177 // callbacks. 1178 // TODO(stuartmorgan): Consider removing the distinction between 1179 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine 1180 // now that the log upload flow is the same for both modes. 1181 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) { 1182 state_ = SENDING_CURRENT_LOGS; 1183 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */); 1184 return; 1185 } 1186 // If there are unsent logs, send the next one. If not, start the asynchronous 1187 // process of finalizing the current log for upload. 1188 if (state_ == SENDING_OLD_LOGS) { 1189 DCHECK(log_manager_.has_unsent_logs()); 1190 log_manager_.StageNextLogForUpload(); 1191 SendStagedLog(); 1192 } else { 1193 StartFinalLogInfoCollection(); 1194 } 1195 } 1196 1197 void MetricsService::StartFinalLogInfoCollection() { 1198 // Begin the multi-step process of collecting memory usage histograms: 1199 // First spawn a task to collect the memory details; when that task is 1200 // finished, it will call OnMemoryDetailCollectionDone. That will in turn 1201 // call HistogramSynchronization to collect histograms from all renderers and 1202 // then call OnHistogramSynchronizationDone to continue processing. 1203 DCHECK(!waiting_for_asynchronous_reporting_step_); 1204 waiting_for_asynchronous_reporting_step_ = true; 1205 1206 base::Closure callback = 1207 base::Bind(&MetricsService::OnMemoryDetailCollectionDone, 1208 self_ptr_factory_.GetWeakPtr()); 1209 1210 scoped_refptr<MetricsMemoryDetails> details( 1211 new MetricsMemoryDetails(callback)); 1212 details->StartFetch(MemoryDetails::UPDATE_USER_METRICS); 1213 1214 // Collect WebCore cache information to put into a histogram. 1215 for (content::RenderProcessHost::iterator i( 1216 content::RenderProcessHost::AllHostsIterator()); 1217 !i.IsAtEnd(); i.Advance()) 1218 i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats()); 1219 } 1220 1221 void MetricsService::OnMemoryDetailCollectionDone() { 1222 DCHECK(IsSingleThreaded()); 1223 // This function should only be called as the callback from an ansynchronous 1224 // step. 1225 DCHECK(waiting_for_asynchronous_reporting_step_); 1226 1227 // Create a callback_task for OnHistogramSynchronizationDone. 1228 base::Closure callback = base::Bind( 1229 &MetricsService::OnHistogramSynchronizationDone, 1230 self_ptr_factory_.GetWeakPtr()); 1231 1232 // Set up the callback to task to call after we receive histograms from all 1233 // child processes. Wait time specifies how long to wait before absolutely 1234 // calling us back on the task. 1235 content::FetchHistogramsAsynchronously( 1236 base::MessageLoop::current(), callback, 1237 base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration)); 1238 } 1239 1240 void MetricsService::OnHistogramSynchronizationDone() { 1241 DCHECK(IsSingleThreaded()); 1242 // This function should only be called as the callback from an ansynchronous 1243 // step. 1244 DCHECK(waiting_for_asynchronous_reporting_step_); 1245 1246 waiting_for_asynchronous_reporting_step_ = false; 1247 OnFinalLogInfoCollectionDone(); 1248 } 1249 1250 void MetricsService::OnFinalLogInfoCollectionDone() { 1251 // If somehow there is a fetch in progress, we return and hope things work 1252 // out. The scheduler isn't informed since if this happens, the scheduler 1253 // will get a response from the upload. 1254 DCHECK(!current_fetch_.get()); 1255 if (current_fetch_.get()) 1256 return; 1257 1258 // Abort if metrics were turned off during the final info gathering. 1259 if (!recording_active()) { 1260 scheduler_->Stop(); 1261 scheduler_->UploadCancelled(); 1262 return; 1263 } 1264 1265 StageNewLog(); 1266 1267 // If logs shouldn't be uploaded, stop here. It's important that this check 1268 // be after StageNewLog(), otherwise the previous logs will never be loaded, 1269 // and thus the open log won't be persisted. 1270 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading 1271 // of previous logs to not require running part of the upload logic. 1272 // http://crbug.com/157337 1273 if (!reporting_active()) { 1274 scheduler_->Stop(); 1275 scheduler_->UploadCancelled(); 1276 return; 1277 } 1278 1279 SendStagedLog(); 1280 } 1281 1282 void MetricsService::StageNewLog() { 1283 if (log_manager_.has_staged_log()) 1284 return; 1285 1286 switch (state_) { 1287 case INITIALIZED: 1288 case INIT_TASK_SCHEDULED: // We should be further along by now. 1289 NOTREACHED(); 1290 return; 1291 1292 case INIT_TASK_DONE: 1293 PrepareInitialLog(); 1294 DCHECK_EQ(INIT_TASK_DONE, state_); 1295 log_manager_.LoadPersistedUnsentLogs(); 1296 state_ = INITIAL_LOG_READY; 1297 break; 1298 1299 case SENDING_OLD_LOGS: 1300 NOTREACHED(); // Shouldn't be staging a new log during old log sending. 1301 return; 1302 1303 case SENDING_CURRENT_LOGS: 1304 CloseCurrentLog(); 1305 OpenNewLog(); 1306 log_manager_.StageNextLogForUpload(); 1307 break; 1308 1309 default: 1310 NOTREACHED(); 1311 return; 1312 } 1313 1314 DCHECK(log_manager_.has_staged_log()); 1315 } 1316 1317 void MetricsService::PrepareInitialLog() { 1318 DCHECK_EQ(INIT_TASK_DONE, state_); 1319 1320 DCHECK(initial_log_.get()); 1321 initial_log_->set_hardware_class(hardware_class_); 1322 initial_log_->RecordEnvironment(plugins_, google_update_metrics_); 1323 1324 // Histograms only get written to the current log, so make the new log current 1325 // before writing them. 1326 log_manager_.PauseCurrentLog(); 1327 log_manager_.BeginLoggingWithLog(initial_log_.release(), 1328 MetricsLogManager::INITIAL_LOG); 1329 RecordCurrentHistograms(); 1330 log_manager_.FinishCurrentLog(); 1331 log_manager_.ResumePausedLog(); 1332 1333 DCHECK(!log_manager_.has_staged_log()); 1334 log_manager_.StageNextLogForUpload(); 1335 } 1336 1337 void MetricsService::StoreUnsentLogs() { 1338 if (state_ < INITIAL_LOG_READY) 1339 return; // We never Recalled the prior unsent logs. 1340 1341 log_manager_.PersistUnsentLogs(); 1342 } 1343 1344 void MetricsService::SendStagedLog() { 1345 DCHECK(log_manager_.has_staged_log()); 1346 1347 PrepareFetchWithStagedLog(); 1348 1349 bool upload_created = (current_fetch_.get() != NULL); 1350 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created); 1351 if (!upload_created) { 1352 // Compression failed, and log discarded :-/. 1353 // Skip this upload and hope things work out next time. 1354 log_manager_.DiscardStagedLog(); 1355 scheduler_->UploadCancelled(); 1356 return; 1357 } 1358 1359 DCHECK(!waiting_for_asynchronous_reporting_step_); 1360 waiting_for_asynchronous_reporting_step_ = true; 1361 1362 current_fetch_->Start(); 1363 1364 HandleIdleSinceLastTransmission(true); 1365 } 1366 1367 void MetricsService::PrepareFetchWithStagedLog() { 1368 DCHECK(log_manager_.has_staged_log()); 1369 1370 // Prepare the protobuf version. 1371 DCHECK(!current_fetch_.get()); 1372 if (log_manager_.has_staged_log()) { 1373 current_fetch_.reset(net::URLFetcher::Create( 1374 GURL(kServerUrl), net::URLFetcher::POST, this)); 1375 current_fetch_->SetRequestContext( 1376 g_browser_process->system_request_context()); 1377 1378 // Compress the protobufs 50% of the time. This can be used to see if 1379 // compressed protobufs are being mishandled by machines between the 1380 // client/server or monitoring programs/firewalls on the client. 1381 bool gzip_protobuf_before_uploading = 1382 metrics::ShouldGzipProtobufsBeforeUploading(); 1383 if (gzip_protobuf_before_uploading) { 1384 std::string log_text = log_manager_.staged_log_text(); 1385 std::string compressed_log_text; 1386 bool compression_successful = chrome::GzipCompress(log_text, 1387 &compressed_log_text); 1388 DCHECK(compression_successful); 1389 if (compression_successful) { 1390 current_fetch_->SetUploadData(kMimeType, compressed_log_text); 1391 // Tell the server that we're uploading gzipped protobufs. 1392 current_fetch_->SetExtraRequestHeaders("content-encoding: gzip"); 1393 UMA_HISTOGRAM_PERCENTAGE( 1394 "UMA.ProtoCompressionRatio", 1395 100 * compressed_log_text.size() / log_text.size()); 1396 UMA_HISTOGRAM_CUSTOM_COUNTS( 1397 "UMA.ProtoGzippedKBSaved", 1398 (log_text.size() - compressed_log_text.size()) / 1024, 1399 1, 2000, 50); 1400 } 1401 } else { 1402 current_fetch_->SetUploadData(kMimeType, log_manager_.staged_log_text()); 1403 } 1404 UMA_HISTOGRAM_BOOLEAN("UMA.ProtoGzipped", 1405 gzip_protobuf_before_uploading); 1406 1407 // We already drop cookies server-side, but we might as well strip them out 1408 // client-side as well. 1409 current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | 1410 net::LOAD_DO_NOT_SEND_COOKIES); 1411 } 1412 } 1413 1414 void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) { 1415 DCHECK(waiting_for_asynchronous_reporting_step_); 1416 1417 // We're not allowed to re-use the existing |URLFetcher|s, so free them here. 1418 // Note however that |source| is aliased to the fetcher, so we should be 1419 // careful not to delete it too early. 1420 DCHECK_EQ(current_fetch_.get(), source); 1421 scoped_ptr<net::URLFetcher> s(current_fetch_.Pass()); 1422 1423 int response_code = source->GetResponseCode(); 1424 1425 // Log a histogram to track response success vs. failure rates. 1426 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf", 1427 ResponseCodeToStatus(response_code), 1428 NUM_RESPONSE_STATUSES); 1429 1430 // If the upload was provisionally stored, drop it now that the upload is 1431 // known to have gone through. 1432 log_manager_.DiscardLastProvisionalStore(); 1433 1434 bool upload_succeeded = response_code == 200; 1435 1436 // Provide boolean for error recovery (allow us to ignore response_code). 1437 bool discard_log = false; 1438 const size_t log_size = log_manager_.staged_log_text().length(); 1439 if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) { 1440 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded", 1441 static_cast<int>(log_size)); 1442 discard_log = true; 1443 } else if (response_code == 400) { 1444 // Bad syntax. Retransmission won't work. 1445 discard_log = true; 1446 } 1447 1448 if (upload_succeeded || discard_log) 1449 log_manager_.DiscardStagedLog(); 1450 1451 waiting_for_asynchronous_reporting_step_ = false; 1452 1453 if (!log_manager_.has_staged_log()) { 1454 switch (state_) { 1455 case INITIAL_LOG_READY: 1456 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS 1457 : SENDING_CURRENT_LOGS; 1458 break; 1459 1460 case SENDING_OLD_LOGS: 1461 // Store the updated list to disk now that the removed log is uploaded. 1462 StoreUnsentLogs(); 1463 if (!log_manager_.has_unsent_logs()) 1464 state_ = SENDING_CURRENT_LOGS; 1465 break; 1466 1467 case SENDING_CURRENT_LOGS: 1468 break; 1469 1470 default: 1471 NOTREACHED(); 1472 break; 1473 } 1474 1475 if (log_manager_.has_unsent_logs()) 1476 DCHECK_LT(state_, SENDING_CURRENT_LOGS); 1477 } 1478 1479 // Error 400 indicates a problem with the log, not with the server, so 1480 // don't consider that a sign that the server is in trouble. 1481 bool server_is_healthy = upload_succeeded || response_code == 400; 1482 scheduler_->UploadFinished(server_is_healthy, log_manager_.has_unsent_logs()); 1483 1484 // Collect network stats if UMA upload succeeded. 1485 IOThread* io_thread = g_browser_process->io_thread(); 1486 if (server_is_healthy && io_thread) { 1487 chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread); 1488 chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread( 1489 http_pipelining_test_server_, io_thread); 1490 #if defined(OS_WIN) 1491 chrome::CollectTimeTicksStats(); 1492 #endif 1493 } 1494 } 1495 1496 void MetricsService::IncrementPrefValue(const char* path) { 1497 PrefService* pref = g_browser_process->local_state(); 1498 DCHECK(pref); 1499 int value = pref->GetInteger(path); 1500 pref->SetInteger(path, value + 1); 1501 } 1502 1503 void MetricsService::IncrementLongPrefsValue(const char* path) { 1504 PrefService* pref = g_browser_process->local_state(); 1505 DCHECK(pref); 1506 int64 value = pref->GetInt64(path); 1507 pref->SetInt64(path, value + 1); 1508 } 1509 1510 void MetricsService::LogLoadStarted(content::WebContents* web_contents) { 1511 content::RecordAction(content::UserMetricsAction("PageLoad")); 1512 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2); 1513 IncrementPrefValue(prefs::kStabilityPageLoadCount); 1514 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount); 1515 // We need to save the prefs, as page load count is a critical stat, and it 1516 // might be lost due to a crash :-(. 1517 } 1518 1519 void MetricsService::LogRendererCrash(content::RenderProcessHost* host, 1520 base::TerminationStatus status, 1521 int exit_code) { 1522 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext()); 1523 ExtensionService* service = profile->GetExtensionService(); 1524 bool was_extension_process = 1525 service && service->process_map()->Contains(host->GetID()); 1526 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || 1527 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { 1528 if (was_extension_process) { 1529 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount); 1530 1531 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension", 1532 MapCrashExitCodeForHistogram(exit_code)); 1533 } else { 1534 IncrementPrefValue(prefs::kStabilityRendererCrashCount); 1535 1536 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer", 1537 MapCrashExitCodeForHistogram(exit_code)); 1538 } 1539 1540 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes", 1541 was_extension_process ? 2 : 1); 1542 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { 1543 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills", 1544 was_extension_process ? 2 : 1); 1545 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) { 1546 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive", 1547 was_extension_process ? 2 : 1); 1548 } 1549 } 1550 1551 void MetricsService::LogRendererHang() { 1552 IncrementPrefValue(prefs::kStabilityRendererHangCount); 1553 } 1554 1555 bool MetricsService::UmaMetricsProperlyShutdown() { 1556 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN || 1557 clean_shutdown_status_ == NEED_TO_SHUTDOWN); 1558 return clean_shutdown_status_ == CLEANLY_SHUTDOWN; 1559 } 1560 1561 void MetricsService::LogCleanShutdown() { 1562 // Redundant hack to write pref ASAP. 1563 MarkAppCleanShutdownAndCommit(); 1564 1565 // Redundant setting to assure that we always reset this value at shutdown 1566 // (and that we don't use some alternate path, and not call LogCleanShutdown). 1567 clean_shutdown_status_ = CLEANLY_SHUTDOWN; 1568 1569 RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true); 1570 } 1571 1572 #if defined(OS_CHROMEOS) 1573 void MetricsService::LogChromeOSCrash(const std::string &crash_type) { 1574 if (crash_type == "user") 1575 IncrementPrefValue(prefs::kStabilityOtherUserCrashCount); 1576 else if (crash_type == "kernel") 1577 IncrementPrefValue(prefs::kStabilityKernelCrashCount); 1578 else if (crash_type == "uncleanshutdown") 1579 IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount); 1580 else 1581 NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type; 1582 // Wake up metrics logs sending if necessary now that new 1583 // log data is available. 1584 HandleIdleSinceLastTransmission(false); 1585 } 1586 #endif // OS_CHROMEOS 1587 1588 void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) { 1589 content::WebPluginInfo plugin; 1590 bool success = 1591 content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path, 1592 &plugin); 1593 DCHECK(success); 1594 ChildProcessStats& stats = child_process_stats_buffer_[plugin.name]; 1595 // Initialize the type if this entry is new. 1596 if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) { 1597 // The plug-in process might not actually of type PLUGIN (which means 1598 // NPAPI), but we only care that it is *a* plug-in process. 1599 stats.process_type = content::PROCESS_TYPE_PLUGIN; 1600 } else { 1601 DCHECK(IsPluginProcess(stats.process_type)); 1602 } 1603 stats.loading_errors++; 1604 } 1605 1606 MetricsService::ChildProcessStats& MetricsService::GetChildProcessStats( 1607 const content::ChildProcessData& data) { 1608 const string16& child_name = data.name; 1609 if (!ContainsKey(child_process_stats_buffer_, child_name)) { 1610 child_process_stats_buffer_[child_name] = 1611 ChildProcessStats(data.process_type); 1612 } 1613 return child_process_stats_buffer_[child_name]; 1614 } 1615 1616 void MetricsService::RecordPluginChanges(PrefService* pref) { 1617 ListPrefUpdate update(pref, prefs::kStabilityPluginStats); 1618 ListValue* plugins = update.Get(); 1619 DCHECK(plugins); 1620 1621 for (ListValue::iterator value_iter = plugins->begin(); 1622 value_iter != plugins->end(); ++value_iter) { 1623 if (!(*value_iter)->IsType(Value::TYPE_DICTIONARY)) { 1624 NOTREACHED(); 1625 continue; 1626 } 1627 1628 DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*value_iter); 1629 std::string plugin_name; 1630 plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name); 1631 if (plugin_name.empty()) { 1632 NOTREACHED(); 1633 continue; 1634 } 1635 1636 // TODO(viettrungluu): remove conversions 1637 string16 name16 = UTF8ToUTF16(plugin_name); 1638 if (child_process_stats_buffer_.find(name16) == 1639 child_process_stats_buffer_.end()) { 1640 continue; 1641 } 1642 1643 ChildProcessStats stats = child_process_stats_buffer_[name16]; 1644 if (stats.process_launches) { 1645 int launches = 0; 1646 plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches); 1647 launches += stats.process_launches; 1648 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches); 1649 } 1650 if (stats.process_crashes) { 1651 int crashes = 0; 1652 plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes); 1653 crashes += stats.process_crashes; 1654 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes); 1655 } 1656 if (stats.instances) { 1657 int instances = 0; 1658 plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances); 1659 instances += stats.instances; 1660 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances); 1661 } 1662 if (stats.loading_errors) { 1663 int loading_errors = 0; 1664 plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors, 1665 &loading_errors); 1666 loading_errors += stats.loading_errors; 1667 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors, 1668 loading_errors); 1669 } 1670 1671 child_process_stats_buffer_.erase(name16); 1672 } 1673 1674 // Now go through and add dictionaries for plugins that didn't already have 1675 // reports in Local State. 1676 for (std::map<string16, ChildProcessStats>::iterator cache_iter = 1677 child_process_stats_buffer_.begin(); 1678 cache_iter != child_process_stats_buffer_.end(); ++cache_iter) { 1679 ChildProcessStats stats = cache_iter->second; 1680 1681 // Insert only plugins information into the plugins list. 1682 if (!IsPluginProcess(stats.process_type)) 1683 continue; 1684 1685 // TODO(viettrungluu): remove conversion 1686 std::string plugin_name = UTF16ToUTF8(cache_iter->first); 1687 1688 DictionaryValue* plugin_dict = new DictionaryValue; 1689 1690 plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name); 1691 plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, 1692 stats.process_launches); 1693 plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, 1694 stats.process_crashes); 1695 plugin_dict->SetInteger(prefs::kStabilityPluginInstances, 1696 stats.instances); 1697 plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors, 1698 stats.loading_errors); 1699 plugins->Append(plugin_dict); 1700 } 1701 child_process_stats_buffer_.clear(); 1702 } 1703 1704 bool MetricsService::CanLogNotification() { 1705 // We simply don't log anything to UMA if there is a single incognito 1706 // session visible. The problem is that we always notify using the orginal 1707 // profile in order to simplify notification processing. 1708 return !chrome::IsOffTheRecordSessionActive(); 1709 } 1710 1711 void MetricsService::RecordBooleanPrefValue(const char* path, bool value) { 1712 DCHECK(IsSingleThreaded()); 1713 1714 PrefService* pref = g_browser_process->local_state(); 1715 DCHECK(pref); 1716 1717 pref->SetBoolean(path, value); 1718 RecordCurrentState(pref); 1719 } 1720 1721 void MetricsService::RecordCurrentState(PrefService* pref) { 1722 pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT()); 1723 1724 RecordPluginChanges(pref); 1725 } 1726 1727 // static 1728 bool MetricsService::IsPluginProcess(int process_type) { 1729 return (process_type == content::PROCESS_TYPE_PLUGIN || 1730 process_type == content::PROCESS_TYPE_PPAPI_PLUGIN || 1731 process_type == content::PROCESS_TYPE_PPAPI_BROKER); 1732 } 1733 1734 #if defined(OS_CHROMEOS) 1735 void MetricsService::StartExternalMetrics() { 1736 external_metrics_ = new chromeos::ExternalMetrics; 1737 external_metrics_->Start(); 1738 } 1739 #endif 1740 1741 // static 1742 bool MetricsServiceHelper::IsMetricsReportingEnabled() { 1743 bool result = false; 1744 const PrefService* local_state = g_browser_process->local_state(); 1745 if (local_state) { 1746 const PrefService::Preference* uma_pref = 1747 local_state->FindPreference(prefs::kMetricsReportingEnabled); 1748 if (uma_pref) { 1749 bool success = uma_pref->GetValue()->GetAsBoolean(&result); 1750 DCHECK(success); 1751 } 1752 } 1753 return result; 1754 } 1755