1 // Copyright 2014 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 Chrome (from 26 // startup, to browser shutdown). An initial log is generally transmitted some 27 // short time (1 minute?) after startup, and includes stats such as recent crash 28 // info, the number and types of plugins, etc. The external server's response 29 // to the initial log conceptually tells this MS if it should continue 30 // transmitting logs (during this session). The server response can actually be 31 // much more detailed, and always includes (at a minimum) how often additional 32 // 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 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 is 53 // closed (including snapshotting histograms), and persisted, for potential 54 // 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 // states, 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 finish. 81 // INIT_TASK_DONE, // Waiting for timer to send initial log. 82 // SENDING_INITIAL_STABILITY_LOG, // Initial stability log being sent. 83 // SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent. 84 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. 85 // SENDING_CURRENT_LOGS, // Sending ongoing logs as they acrue. 86 // 87 // In more detail, we have: 88 // 89 // INITIALIZED, // Constructor was called. 90 // The MS has been constructed, but has taken no actions to compose the 91 // initial log. 92 // 93 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish. 94 // Typically about 30 seconds after startup, a task is sent to a second thread 95 // (the file thread) to perform deferred (lower priority and slower) 96 // initialization steps such as getting the list of plugins. That task will 97 // (when complete) make an async callback (via a Task) to indicate the 98 // completion. 99 // 100 // INIT_TASK_DONE, // Waiting for timer to send initial log. 101 // The callback has arrived, and it is now possible for an initial log to be 102 // created. This callback typically arrives back less than one second after 103 // the deferred init task is dispatched. 104 // 105 // SENDING_INITIAL_STABILITY_LOG, // Initial stability log being sent. 106 // During initialization, if a crash occurred during the previous session, an 107 // initial stability log will be generated and registered with the log manager. 108 // This state will be entered if a stability log was prepared during metrics 109 // service initialization (in InitializeMetricsRecordingState()) and is waiting 110 // to be transmitted when it's time to send up the first log (per the reporting 111 // scheduler). If there is no initial stability log (e.g. there was no previous 112 // crash), then this state will be skipped and the state will advance to 113 // SENDING_INITIAL_METRICS_LOG. 114 // 115 // SENDING_INITIAL_METRICS_LOG, // Initial metrics log being sent. 116 // This state is entered after the initial metrics log has been composed, and 117 // prepared for transmission. This happens after SENDING_INITIAL_STABILITY_LOG 118 // if there was an initial stability log (see above). It is also the case that 119 // any previously unsent logs have been loaded into instance variables for 120 // possible transmission. 121 // 122 // SENDING_OLD_LOGS, // Sending unsent logs from previous session. 123 // This state indicates that the initial log for this session has been 124 // successfully sent and it is now time to send any logs that were 125 // saved from previous sessions. All such logs will be transmitted before 126 // exiting this state, and proceeding with ongoing logs from the current session 127 // (see next state). 128 // 129 // SENDING_CURRENT_LOGS, // Sending standard current logs as they accrue. 130 // Current logs are being accumulated. Typically every 20 minutes a log is 131 // closed and finalized for transmission, at the same time as a new log is 132 // started. 133 // 134 // The progression through the above states is simple, and sequential, in the 135 // most common use cases. States proceed from INITIAL to SENDING_CURRENT_LOGS, 136 // and remain in the latter until shutdown. 137 // 138 // The one unusual case is when the user asks that we stop logging. When that 139 // happens, any staged (transmission in progress) log is persisted, and any log 140 // that is currently accumulating is also finalized and persisted. We then 141 // regress back to the SEND_OLD_LOGS state in case the user enables log 142 // recording again during this session. This way anything we have persisted 143 // will be sent automatically if/when we progress back to SENDING_CURRENT_LOG 144 // state. 145 // 146 // Another similar case is on mobile, when the application is backgrounded and 147 // then foregrounded again. Backgrounding created new "old" stored logs, so the 148 // state drops back from SENDING_CURRENT_LOGS to SENDING_OLD_LOGS so those logs 149 // will be sent. 150 // 151 // Also note that whenever we successfully send an old log, we mirror the list 152 // of logs into the PrefService. This ensures that IF we crash, we won't start 153 // up and retransmit our old logs again. 154 // 155 // Due to race conditions, it is always possible that a log file could be sent 156 // twice. For example, if a log file is sent, but not yet acknowledged by 157 // the external server, and the user shuts down, then a copy of the log may be 158 // saved for re-transmission. These duplicates could be filtered out server 159 // side, but are not expected to be a significant problem. 160 // 161 // 162 //------------------------------------------------------------------------------ 163 164 #include "components/metrics/metrics_service.h" 165 166 #include <algorithm> 167 168 #include "base/bind.h" 169 #include "base/callback.h" 170 #include "base/metrics/histogram.h" 171 #include "base/metrics/histogram_base.h" 172 #include "base/metrics/histogram_samples.h" 173 #include "base/metrics/sparse_histogram.h" 174 #include "base/metrics/statistics_recorder.h" 175 #include "base/prefs/pref_registry_simple.h" 176 #include "base/prefs/pref_service.h" 177 #include "base/strings/string_number_conversions.h" 178 #include "base/strings/utf_string_conversions.h" 179 #include "base/threading/platform_thread.h" 180 #include "base/threading/thread.h" 181 #include "base/threading/thread_restrictions.h" 182 #include "base/time/time.h" 183 #include "base/tracked_objects.h" 184 #include "base/values.h" 185 #include "components/metrics/metrics_log.h" 186 #include "components/metrics/metrics_log_manager.h" 187 #include "components/metrics/metrics_log_uploader.h" 188 #include "components/metrics/metrics_pref_names.h" 189 #include "components/metrics/metrics_reporting_scheduler.h" 190 #include "components/metrics/metrics_service_client.h" 191 #include "components/metrics/metrics_state_manager.h" 192 #include "components/variations/entropy_provider.h" 193 194 namespace metrics { 195 196 namespace { 197 198 // Check to see that we're being called on only one thread. 199 bool IsSingleThreaded() { 200 static base::PlatformThreadId thread_id = 0; 201 if (!thread_id) 202 thread_id = base::PlatformThread::CurrentId(); 203 return base::PlatformThread::CurrentId() == thread_id; 204 } 205 206 // The delay, in seconds, after starting recording before doing expensive 207 // initialization work. 208 #if defined(OS_ANDROID) || defined(OS_IOS) 209 // On mobile devices, a significant portion of sessions last less than a minute. 210 // Use a shorter timer on these platforms to avoid losing data. 211 // TODO(dfalcantara): To avoid delaying startup, tighten up initialization so 212 // that it occurs after the user gets their initial page. 213 const int kInitializationDelaySeconds = 5; 214 #else 215 const int kInitializationDelaySeconds = 30; 216 #endif 217 218 // The maximum number of events in a log uploaded to the UMA server. 219 const int kEventLimit = 2400; 220 221 // If an upload fails, and the transmission was over this byte count, then we 222 // will discard the log, and not try to retransmit it. We also don't persist 223 // the log to the prefs for transmission during the next chrome session if this 224 // limit is exceeded. 225 const size_t kUploadLogAvoidRetransmitSize = 100 * 1024; 226 227 // Interval, in minutes, between state saves. 228 const int kSaveStateIntervalMinutes = 5; 229 230 // The metrics server's URL. 231 const char kServerUrl[] = "https://clients4.google.com/uma/v2"; 232 233 // The MIME type for the uploaded metrics data. 234 const char kMimeType[] = "application/vnd.chrome.uma"; 235 236 enum ResponseStatus { 237 UNKNOWN_FAILURE, 238 SUCCESS, 239 BAD_REQUEST, // Invalid syntax or log too large. 240 NO_RESPONSE, 241 NUM_RESPONSE_STATUSES 242 }; 243 244 ResponseStatus ResponseCodeToStatus(int response_code) { 245 switch (response_code) { 246 case -1: 247 return NO_RESPONSE; 248 case 200: 249 return SUCCESS; 250 case 400: 251 return BAD_REQUEST; 252 default: 253 return UNKNOWN_FAILURE; 254 } 255 } 256 257 void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon, 258 PrefService* local_state) { 259 clean_exit_beacon->WriteBeaconValue(true); 260 local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase, 261 MetricsService::SHUTDOWN_COMPLETE); 262 // Start writing right away (write happens on a different thread). 263 local_state->CommitPendingWrite(); 264 } 265 266 } // namespace 267 268 269 SyntheticTrialGroup::SyntheticTrialGroup(uint32 trial, uint32 group) { 270 id.name = trial; 271 id.group = group; 272 } 273 274 SyntheticTrialGroup::~SyntheticTrialGroup() { 275 } 276 277 // static 278 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ = 279 MetricsService::CLEANLY_SHUTDOWN; 280 281 MetricsService::ExecutionPhase MetricsService::execution_phase_ = 282 MetricsService::UNINITIALIZED_PHASE; 283 284 // static 285 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) { 286 DCHECK(IsSingleThreaded()); 287 metrics::MetricsStateManager::RegisterPrefs(registry); 288 MetricsLog::RegisterPrefs(registry); 289 290 registry->RegisterInt64Pref(metrics::prefs::kInstallDate, 0); 291 292 registry->RegisterInt64Pref(metrics::prefs::kStabilityLaunchTimeSec, 0); 293 registry->RegisterInt64Pref(metrics::prefs::kStabilityLastTimestampSec, 0); 294 registry->RegisterStringPref(metrics::prefs::kStabilityStatsVersion, 295 std::string()); 296 registry->RegisterInt64Pref(metrics::prefs::kStabilityStatsBuildTime, 0); 297 registry->RegisterBooleanPref(metrics::prefs::kStabilityExitedCleanly, true); 298 registry->RegisterIntegerPref(metrics::prefs::kStabilityExecutionPhase, 299 UNINITIALIZED_PHASE); 300 registry->RegisterBooleanPref(metrics::prefs::kStabilitySessionEndCompleted, 301 true); 302 registry->RegisterIntegerPref(metrics::prefs::kMetricsSessionID, -1); 303 304 registry->RegisterListPref(metrics::prefs::kMetricsInitialLogs); 305 registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogs); 306 307 registry->RegisterInt64Pref(metrics::prefs::kUninstallLaunchCount, 0); 308 registry->RegisterInt64Pref(metrics::prefs::kUninstallMetricsUptimeSec, 0); 309 } 310 311 MetricsService::MetricsService(metrics::MetricsStateManager* state_manager, 312 metrics::MetricsServiceClient* client, 313 PrefService* local_state) 314 : log_manager_(local_state, kUploadLogAvoidRetransmitSize), 315 histogram_snapshot_manager_(this), 316 state_manager_(state_manager), 317 client_(client), 318 local_state_(local_state), 319 clean_exit_beacon_(client->GetRegistryBackupKey(), local_state), 320 recording_active_(false), 321 reporting_active_(false), 322 test_mode_active_(false), 323 state_(INITIALIZED), 324 has_initial_stability_log_(false), 325 log_upload_in_progress_(false), 326 idle_since_last_transmission_(false), 327 session_id_(-1), 328 self_ptr_factory_(this), 329 state_saver_factory_(this) { 330 DCHECK(IsSingleThreaded()); 331 DCHECK(state_manager_); 332 DCHECK(client_); 333 DCHECK(local_state_); 334 335 // Set the install date if this is our first run. 336 int64 install_date = local_state_->GetInt64(metrics::prefs::kInstallDate); 337 if (install_date == 0) { 338 local_state_->SetInt64(metrics::prefs::kInstallDate, 339 base::Time::Now().ToTimeT()); 340 } 341 } 342 343 MetricsService::~MetricsService() { 344 DisableRecording(); 345 } 346 347 void MetricsService::InitializeMetricsRecordingState() { 348 InitializeMetricsState(); 349 350 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload, 351 self_ptr_factory_.GetWeakPtr()); 352 scheduler_.reset(new MetricsReportingScheduler(callback)); 353 } 354 355 void MetricsService::Start() { 356 HandleIdleSinceLastTransmission(false); 357 EnableRecording(); 358 EnableReporting(); 359 } 360 361 bool MetricsService::StartIfMetricsReportingEnabled() { 362 const bool enabled = state_manager_->IsMetricsReportingEnabled(); 363 if (enabled) 364 Start(); 365 return enabled; 366 } 367 368 void MetricsService::StartRecordingForTests() { 369 test_mode_active_ = true; 370 EnableRecording(); 371 DisableReporting(); 372 } 373 374 void MetricsService::Stop() { 375 HandleIdleSinceLastTransmission(false); 376 DisableReporting(); 377 DisableRecording(); 378 } 379 380 void MetricsService::EnableReporting() { 381 if (reporting_active_) 382 return; 383 reporting_active_ = true; 384 StartSchedulerIfNecessary(); 385 } 386 387 void MetricsService::DisableReporting() { 388 reporting_active_ = false; 389 } 390 391 std::string MetricsService::GetClientId() { 392 return state_manager_->client_id(); 393 } 394 395 int64 MetricsService::GetInstallDate() { 396 return local_state_->GetInt64(metrics::prefs::kInstallDate); 397 } 398 399 scoped_ptr<const base::FieldTrial::EntropyProvider> 400 MetricsService::CreateEntropyProvider() { 401 // TODO(asvitkine): Refactor the code so that MetricsService does not expose 402 // this method. 403 return state_manager_->CreateEntropyProvider(); 404 } 405 406 void MetricsService::EnableRecording() { 407 DCHECK(IsSingleThreaded()); 408 409 if (recording_active_) 410 return; 411 recording_active_ = true; 412 413 state_manager_->ForceClientIdCreation(); 414 client_->SetMetricsClientId(state_manager_->client_id()); 415 if (!log_manager_.current_log()) 416 OpenNewLog(); 417 418 for (size_t i = 0; i < metrics_providers_.size(); ++i) 419 metrics_providers_[i]->OnRecordingEnabled(); 420 421 base::RemoveActionCallback(action_callback_); 422 action_callback_ = base::Bind(&MetricsService::OnUserAction, 423 base::Unretained(this)); 424 base::AddActionCallback(action_callback_); 425 } 426 427 void MetricsService::DisableRecording() { 428 DCHECK(IsSingleThreaded()); 429 430 if (!recording_active_) 431 return; 432 recording_active_ = false; 433 434 base::RemoveActionCallback(action_callback_); 435 436 for (size_t i = 0; i < metrics_providers_.size(); ++i) 437 metrics_providers_[i]->OnRecordingDisabled(); 438 439 PushPendingLogsToPersistentStorage(); 440 } 441 442 bool MetricsService::recording_active() const { 443 DCHECK(IsSingleThreaded()); 444 return recording_active_; 445 } 446 447 bool MetricsService::reporting_active() const { 448 DCHECK(IsSingleThreaded()); 449 return reporting_active_; 450 } 451 452 void MetricsService::RecordDelta(const base::HistogramBase& histogram, 453 const base::HistogramSamples& snapshot) { 454 log_manager_.current_log()->RecordHistogramDelta(histogram.histogram_name(), 455 snapshot); 456 } 457 458 void MetricsService::InconsistencyDetected( 459 base::HistogramBase::Inconsistency problem) { 460 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowser", 461 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE); 462 } 463 464 void MetricsService::UniqueInconsistencyDetected( 465 base::HistogramBase::Inconsistency problem) { 466 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowserUnique", 467 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE); 468 } 469 470 void MetricsService::InconsistencyDetectedInLoggedCount(int amount) { 471 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotBrowser", 472 std::abs(amount)); 473 } 474 475 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) { 476 // If there wasn't a lot of action, maybe the computer was asleep, in which 477 // case, the log transmissions should have stopped. Here we start them up 478 // again. 479 if (!in_idle && idle_since_last_transmission_) 480 StartSchedulerIfNecessary(); 481 idle_since_last_transmission_ = in_idle; 482 } 483 484 void MetricsService::OnApplicationNotIdle() { 485 if (recording_active_) 486 HandleIdleSinceLastTransmission(false); 487 } 488 489 void MetricsService::RecordStartOfSessionEnd() { 490 LogCleanShutdown(); 491 RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, false); 492 } 493 494 void MetricsService::RecordCompletedSessionEnd() { 495 LogCleanShutdown(); 496 RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, true); 497 } 498 499 #if defined(OS_ANDROID) || defined(OS_IOS) 500 void MetricsService::OnAppEnterBackground() { 501 scheduler_->Stop(); 502 503 MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_); 504 505 // At this point, there's no way of knowing when the process will be 506 // killed, so this has to be treated similar to a shutdown, closing and 507 // persisting all logs. Unlinke a shutdown, the state is primed to be ready 508 // to continue logging and uploading if the process does return. 509 if (recording_active() && state_ >= SENDING_INITIAL_STABILITY_LOG) { 510 PushPendingLogsToPersistentStorage(); 511 // Persisting logs closes the current log, so start recording a new log 512 // immediately to capture any background work that might be done before the 513 // process is killed. 514 OpenNewLog(); 515 } 516 } 517 518 void MetricsService::OnAppEnterForeground() { 519 clean_exit_beacon_.WriteBeaconValue(false); 520 StartSchedulerIfNecessary(); 521 } 522 #else 523 void MetricsService::LogNeedForCleanShutdown() { 524 clean_exit_beacon_.WriteBeaconValue(false); 525 // Redundant setting to be sure we call for a clean shutdown. 526 clean_shutdown_status_ = NEED_TO_SHUTDOWN; 527 } 528 #endif // defined(OS_ANDROID) || defined(OS_IOS) 529 530 // static 531 void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase, 532 PrefService* local_state) { 533 execution_phase_ = execution_phase; 534 local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase, 535 execution_phase_); 536 } 537 538 void MetricsService::RecordBreakpadRegistration(bool success) { 539 if (!success) 540 IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationFail); 541 else 542 IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationSuccess); 543 } 544 545 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) { 546 if (!has_debugger) 547 IncrementPrefValue(metrics::prefs::kStabilityDebuggerNotPresent); 548 else 549 IncrementPrefValue(metrics::prefs::kStabilityDebuggerPresent); 550 } 551 552 //------------------------------------------------------------------------------ 553 // private methods 554 //------------------------------------------------------------------------------ 555 556 557 //------------------------------------------------------------------------------ 558 // Initialization methods 559 560 void MetricsService::InitializeMetricsState() { 561 const int64 buildtime = MetricsLog::GetBuildTime(); 562 const std::string version = client_->GetVersionString(); 563 bool version_changed = false; 564 if (local_state_->GetInt64(prefs::kStabilityStatsBuildTime) != buildtime || 565 local_state_->GetString(prefs::kStabilityStatsVersion) != version) { 566 local_state_->SetString(metrics::prefs::kStabilityStatsVersion, version); 567 local_state_->SetInt64(metrics::prefs::kStabilityStatsBuildTime, buildtime); 568 version_changed = true; 569 } 570 571 log_manager_.LoadPersistedUnsentLogs(); 572 573 session_id_ = local_state_->GetInteger(metrics::prefs::kMetricsSessionID); 574 575 if (!clean_exit_beacon_.exited_cleanly()) { 576 IncrementPrefValue(metrics::prefs::kStabilityCrashCount); 577 // Reset flag, and wait until we call LogNeedForCleanShutdown() before 578 // monitoring. 579 clean_exit_beacon_.WriteBeaconValue(true); 580 } 581 582 if (!clean_exit_beacon_.exited_cleanly() || ProvidersHaveStabilityMetrics()) { 583 // TODO(rtenneti): On windows, consider saving/getting execution_phase from 584 // the registry. 585 int execution_phase = 586 local_state_->GetInteger(metrics::prefs::kStabilityExecutionPhase); 587 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase", 588 execution_phase); 589 590 // If the previous session didn't exit cleanly, or if any provider 591 // explicitly requests it, prepare an initial stability log - 592 // provided UMA is enabled. 593 if (state_manager_->IsMetricsReportingEnabled()) 594 PrepareInitialStabilityLog(); 595 } 596 597 // If no initial stability log was generated and there was a version upgrade, 598 // clear the stability stats from the previous version (so that they don't get 599 // attributed to the current version). This could otherwise happen due to a 600 // number of different edge cases, such as if the last version crashed before 601 // it could save off a system profile or if UMA reporting is disabled (which 602 // normally results in stats being accumulated). 603 if (!has_initial_stability_log_ && version_changed) { 604 for (size_t i = 0; i < metrics_providers_.size(); ++i) 605 metrics_providers_[i]->ClearSavedStabilityMetrics(); 606 607 // Reset the prefs that are managed by MetricsService/MetricsLog directly. 608 local_state_->SetInteger(prefs::kStabilityCrashCount, 0); 609 local_state_->SetInteger(prefs::kStabilityExecutionPhase, 610 UNINITIALIZED_PHASE); 611 local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0); 612 local_state_->SetInteger(prefs::kStabilityLaunchCount, 0); 613 local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true); 614 } 615 616 // Update session ID. 617 ++session_id_; 618 local_state_->SetInteger(metrics::prefs::kMetricsSessionID, session_id_); 619 620 // Stability bookkeeping 621 IncrementPrefValue(metrics::prefs::kStabilityLaunchCount); 622 623 DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_); 624 SetExecutionPhase(START_METRICS_RECORDING, local_state_); 625 626 if (!local_state_->GetBoolean( 627 metrics::prefs::kStabilitySessionEndCompleted)) { 628 IncrementPrefValue(metrics::prefs::kStabilityIncompleteSessionEndCount); 629 // This is marked false when we get a WM_ENDSESSION. 630 local_state_->SetBoolean(metrics::prefs::kStabilitySessionEndCompleted, 631 true); 632 } 633 634 // Call GetUptimes() for the first time, thus allowing all later calls 635 // to record incremental uptimes accurately. 636 base::TimeDelta ignored_uptime_parameter; 637 base::TimeDelta startup_uptime; 638 GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter); 639 DCHECK_EQ(0, startup_uptime.InMicroseconds()); 640 // For backwards compatibility, leave this intact in case Omaha is checking 641 // them. metrics::prefs::kStabilityLastTimestampSec may also be useless now. 642 // TODO(jar): Delete these if they have no uses. 643 local_state_->SetInt64(metrics::prefs::kStabilityLaunchTimeSec, 644 base::Time::Now().ToTimeT()); 645 646 // Bookkeeping for the uninstall metrics. 647 IncrementLongPrefsValue(metrics::prefs::kUninstallLaunchCount); 648 649 // Kick off the process of saving the state (so the uptime numbers keep 650 // getting updated) every n minutes. 651 ScheduleNextStateSave(); 652 } 653 654 void MetricsService::OnUserAction(const std::string& action) { 655 if (!ShouldLogEvents()) 656 return; 657 658 log_manager_.current_log()->RecordUserAction(action); 659 HandleIdleSinceLastTransmission(false); 660 } 661 662 void MetricsService::FinishedGatheringInitialMetrics() { 663 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 664 state_ = INIT_TASK_DONE; 665 666 // Create the initial log. 667 if (!initial_metrics_log_.get()) { 668 initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG); 669 NotifyOnDidCreateMetricsLog(); 670 } 671 672 scheduler_->InitTaskComplete(); 673 } 674 675 void MetricsService::GetUptimes(PrefService* pref, 676 base::TimeDelta* incremental_uptime, 677 base::TimeDelta* uptime) { 678 base::TimeTicks now = base::TimeTicks::Now(); 679 // If this is the first call, init |first_updated_time_| and 680 // |last_updated_time_|. 681 if (last_updated_time_.is_null()) { 682 first_updated_time_ = now; 683 last_updated_time_ = now; 684 } 685 *incremental_uptime = now - last_updated_time_; 686 *uptime = now - first_updated_time_; 687 last_updated_time_ = now; 688 689 const int64 incremental_time_secs = incremental_uptime->InSeconds(); 690 if (incremental_time_secs > 0) { 691 int64 metrics_uptime = 692 pref->GetInt64(metrics::prefs::kUninstallMetricsUptimeSec); 693 metrics_uptime += incremental_time_secs; 694 pref->SetInt64(metrics::prefs::kUninstallMetricsUptimeSec, metrics_uptime); 695 } 696 } 697 698 void MetricsService::NotifyOnDidCreateMetricsLog() { 699 DCHECK(IsSingleThreaded()); 700 for (size_t i = 0; i < metrics_providers_.size(); ++i) 701 metrics_providers_[i]->OnDidCreateMetricsLog(); 702 } 703 704 //------------------------------------------------------------------------------ 705 // State save methods 706 707 void MetricsService::ScheduleNextStateSave() { 708 state_saver_factory_.InvalidateWeakPtrs(); 709 710 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 711 base::Bind(&MetricsService::SaveLocalState, 712 state_saver_factory_.GetWeakPtr()), 713 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes)); 714 } 715 716 void MetricsService::SaveLocalState() { 717 RecordCurrentState(local_state_); 718 719 // TODO(jar):110021 Does this run down the batteries???? 720 ScheduleNextStateSave(); 721 } 722 723 724 //------------------------------------------------------------------------------ 725 // Recording control methods 726 727 void MetricsService::OpenNewLog() { 728 DCHECK(!log_manager_.current_log()); 729 730 log_manager_.BeginLoggingWithLog(CreateLog(MetricsLog::ONGOING_LOG)); 731 NotifyOnDidCreateMetricsLog(); 732 if (state_ == INITIALIZED) { 733 // We only need to schedule that run once. 734 state_ = INIT_TASK_SCHEDULED; 735 736 base::MessageLoop::current()->PostDelayedTask( 737 FROM_HERE, 738 base::Bind(&MetricsService::StartGatheringMetrics, 739 self_ptr_factory_.GetWeakPtr()), 740 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); 741 } 742 } 743 744 void MetricsService::StartGatheringMetrics() { 745 client_->StartGatheringMetrics( 746 base::Bind(&MetricsService::FinishedGatheringInitialMetrics, 747 self_ptr_factory_.GetWeakPtr())); 748 } 749 750 void MetricsService::CloseCurrentLog() { 751 if (!log_manager_.current_log()) 752 return; 753 754 // TODO(jar): Integrate bounds on log recording more consistently, so that we 755 // can stop recording logs that are too big much sooner. 756 if (log_manager_.current_log()->num_events() > kEventLimit) { 757 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events", 758 log_manager_.current_log()->num_events()); 759 log_manager_.DiscardCurrentLog(); 760 OpenNewLog(); // Start trivial log to hold our histograms. 761 } 762 763 // Put incremental data (histogram deltas, and realtime stats deltas) at the 764 // end of all log transmissions (initial log handles this separately). 765 // RecordIncrementalStabilityElements only exists on the derived 766 // MetricsLog class. 767 MetricsLog* current_log = log_manager_.current_log(); 768 DCHECK(current_log); 769 std::vector<variations::ActiveGroupId> synthetic_trials; 770 GetCurrentSyntheticFieldTrials(&synthetic_trials); 771 current_log->RecordEnvironment( 772 metrics_providers_.get(), synthetic_trials, GetInstallDate()); 773 base::TimeDelta incremental_uptime; 774 base::TimeDelta uptime; 775 GetUptimes(local_state_, &incremental_uptime, &uptime); 776 current_log->RecordStabilityMetrics(metrics_providers_.get(), 777 incremental_uptime, uptime); 778 779 current_log->RecordGeneralMetrics(metrics_providers_.get()); 780 RecordCurrentHistograms(); 781 782 log_manager_.FinishCurrentLog(); 783 } 784 785 void MetricsService::PushPendingLogsToPersistentStorage() { 786 if (state_ < SENDING_INITIAL_STABILITY_LOG) 787 return; // We didn't and still don't have time to get plugin list etc. 788 789 CloseCurrentLog(); 790 log_manager_.PersistUnsentLogs(); 791 792 // If there was a staged and/or current log, then there is now at least one 793 // log waiting to be uploaded. 794 if (log_manager_.has_unsent_logs()) 795 state_ = SENDING_OLD_LOGS; 796 } 797 798 //------------------------------------------------------------------------------ 799 // Transmission of logs methods 800 801 void MetricsService::StartSchedulerIfNecessary() { 802 // Never schedule cutting or uploading of logs in test mode. 803 if (test_mode_active_) 804 return; 805 806 // Even if reporting is disabled, the scheduler is needed to trigger the 807 // creation of the initial log, which must be done in order for any logs to be 808 // persisted on shutdown or backgrounding. 809 if (recording_active() && 810 (reporting_active() || state_ < SENDING_INITIAL_STABILITY_LOG)) { 811 scheduler_->Start(); 812 } 813 } 814 815 void MetricsService::StartScheduledUpload() { 816 // If we're getting no notifications, then the log won't have much in it, and 817 // it's possible the computer is about to go to sleep, so don't upload and 818 // stop the scheduler. 819 // If recording has been turned off, the scheduler doesn't need to run. 820 // If reporting is off, proceed if the initial log hasn't been created, since 821 // that has to happen in order for logs to be cut and stored when persisting. 822 // TODO(stuartmorgan): Call Stop() on the scheduler when reporting and/or 823 // recording are turned off instead of letting it fire and then aborting. 824 if (idle_since_last_transmission_ || 825 !recording_active() || 826 (!reporting_active() && state_ >= SENDING_INITIAL_STABILITY_LOG)) { 827 scheduler_->Stop(); 828 scheduler_->UploadCancelled(); 829 return; 830 } 831 832 // If the callback was to upload an old log, but there no longer is one, 833 // just report success back to the scheduler to begin the ongoing log 834 // callbacks. 835 // TODO(stuartmorgan): Consider removing the distinction between 836 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine 837 // now that the log upload flow is the same for both modes. 838 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) { 839 state_ = SENDING_CURRENT_LOGS; 840 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */); 841 return; 842 } 843 // If there are unsent logs, send the next one. If not, start the asynchronous 844 // process of finalizing the current log for upload. 845 if (state_ == SENDING_OLD_LOGS) { 846 DCHECK(log_manager_.has_unsent_logs()); 847 log_manager_.StageNextLogForUpload(); 848 SendStagedLog(); 849 } else { 850 client_->CollectFinalMetrics( 851 base::Bind(&MetricsService::OnFinalLogInfoCollectionDone, 852 self_ptr_factory_.GetWeakPtr())); 853 } 854 } 855 856 void MetricsService::OnFinalLogInfoCollectionDone() { 857 // If somehow there is a log upload in progress, we return and hope things 858 // work out. The scheduler isn't informed since if this happens, the scheduler 859 // will get a response from the upload. 860 DCHECK(!log_upload_in_progress_); 861 if (log_upload_in_progress_) 862 return; 863 864 // Abort if metrics were turned off during the final info gathering. 865 if (!recording_active()) { 866 scheduler_->Stop(); 867 scheduler_->UploadCancelled(); 868 return; 869 } 870 871 StageNewLog(); 872 873 // If logs shouldn't be uploaded, stop here. It's important that this check 874 // be after StageNewLog(), otherwise the previous logs will never be loaded, 875 // and thus the open log won't be persisted. 876 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading 877 // of previous logs to not require running part of the upload logic. 878 // http://crbug.com/157337 879 if (!reporting_active()) { 880 scheduler_->Stop(); 881 scheduler_->UploadCancelled(); 882 return; 883 } 884 885 SendStagedLog(); 886 } 887 888 void MetricsService::StageNewLog() { 889 if (log_manager_.has_staged_log()) 890 return; 891 892 switch (state_) { 893 case INITIALIZED: 894 case INIT_TASK_SCHEDULED: // We should be further along by now. 895 NOTREACHED(); 896 return; 897 898 case INIT_TASK_DONE: 899 if (has_initial_stability_log_) { 900 // There's an initial stability log, ready to send. 901 log_manager_.StageNextLogForUpload(); 902 has_initial_stability_log_ = false; 903 state_ = SENDING_INITIAL_STABILITY_LOG; 904 } else { 905 PrepareInitialMetricsLog(); 906 state_ = SENDING_INITIAL_METRICS_LOG; 907 } 908 break; 909 910 case SENDING_OLD_LOGS: 911 NOTREACHED(); // Shouldn't be staging a new log during old log sending. 912 return; 913 914 case SENDING_CURRENT_LOGS: 915 CloseCurrentLog(); 916 OpenNewLog(); 917 log_manager_.StageNextLogForUpload(); 918 break; 919 920 default: 921 NOTREACHED(); 922 return; 923 } 924 925 DCHECK(log_manager_.has_staged_log()); 926 } 927 928 bool MetricsService::ProvidersHaveStabilityMetrics() { 929 // Check whether any metrics provider has stability metrics. 930 for (size_t i = 0; i < metrics_providers_.size(); ++i) { 931 if (metrics_providers_[i]->HasStabilityMetrics()) 932 return true; 933 } 934 935 return false; 936 } 937 938 void MetricsService::PrepareInitialStabilityLog() { 939 DCHECK_EQ(INITIALIZED, state_); 940 941 scoped_ptr<MetricsLog> initial_stability_log( 942 CreateLog(MetricsLog::INITIAL_STABILITY_LOG)); 943 944 // Do not call NotifyOnDidCreateMetricsLog here because the stability 945 // log describes stats from the _previous_ session. 946 947 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs()) 948 return; 949 950 log_manager_.PauseCurrentLog(); 951 log_manager_.BeginLoggingWithLog(initial_stability_log.Pass()); 952 953 // Note: Some stability providers may record stability stats via histograms, 954 // so this call has to be after BeginLoggingWithLog(). 955 log_manager_.current_log()->RecordStabilityMetrics( 956 metrics_providers_.get(), base::TimeDelta(), base::TimeDelta()); 957 RecordCurrentStabilityHistograms(); 958 959 // Note: RecordGeneralMetrics() intentionally not called since this log is for 960 // stability stats from a previous session only. 961 962 log_manager_.FinishCurrentLog(); 963 log_manager_.ResumePausedLog(); 964 965 // Store unsent logs, including the stability log that was just saved, so 966 // that they're not lost in case of a crash before upload time. 967 log_manager_.PersistUnsentLogs(); 968 969 has_initial_stability_log_ = true; 970 } 971 972 void MetricsService::PrepareInitialMetricsLog() { 973 DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG); 974 975 std::vector<variations::ActiveGroupId> synthetic_trials; 976 GetCurrentSyntheticFieldTrials(&synthetic_trials); 977 initial_metrics_log_->RecordEnvironment(metrics_providers_.get(), 978 synthetic_trials, 979 GetInstallDate()); 980 base::TimeDelta incremental_uptime; 981 base::TimeDelta uptime; 982 GetUptimes(local_state_, &incremental_uptime, &uptime); 983 984 // Histograms only get written to the current log, so make the new log current 985 // before writing them. 986 log_manager_.PauseCurrentLog(); 987 log_manager_.BeginLoggingWithLog(initial_metrics_log_.Pass()); 988 989 // Note: Some stability providers may record stability stats via histograms, 990 // so this call has to be after BeginLoggingWithLog(). 991 MetricsLog* current_log = log_manager_.current_log(); 992 current_log->RecordStabilityMetrics(metrics_providers_.get(), 993 base::TimeDelta(), base::TimeDelta()); 994 current_log->RecordGeneralMetrics(metrics_providers_.get()); 995 RecordCurrentHistograms(); 996 997 log_manager_.FinishCurrentLog(); 998 log_manager_.ResumePausedLog(); 999 1000 // Store unsent logs, including the initial log that was just saved, so 1001 // that they're not lost in case of a crash before upload time. 1002 log_manager_.PersistUnsentLogs(); 1003 1004 DCHECK(!log_manager_.has_staged_log()); 1005 log_manager_.StageNextLogForUpload(); 1006 } 1007 1008 void MetricsService::SendStagedLog() { 1009 DCHECK(log_manager_.has_staged_log()); 1010 if (!log_manager_.has_staged_log()) 1011 return; 1012 1013 DCHECK(!log_upload_in_progress_); 1014 log_upload_in_progress_ = true; 1015 1016 if (!log_uploader_) { 1017 log_uploader_ = client_->CreateUploader( 1018 kServerUrl, kMimeType, 1019 base::Bind(&MetricsService::OnLogUploadComplete, 1020 self_ptr_factory_.GetWeakPtr())); 1021 } 1022 1023 const std::string hash = 1024 base::HexEncode(log_manager_.staged_log_hash().data(), 1025 log_manager_.staged_log_hash().size()); 1026 bool success = log_uploader_->UploadLog(log_manager_.staged_log(), hash); 1027 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", success); 1028 if (!success) { 1029 // Skip this upload and hope things work out next time. 1030 log_manager_.DiscardStagedLog(); 1031 scheduler_->UploadCancelled(); 1032 log_upload_in_progress_ = false; 1033 return; 1034 } 1035 1036 HandleIdleSinceLastTransmission(true); 1037 } 1038 1039 1040 void MetricsService::OnLogUploadComplete(int response_code) { 1041 DCHECK(log_upload_in_progress_); 1042 log_upload_in_progress_ = false; 1043 1044 // Log a histogram to track response success vs. failure rates. 1045 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf", 1046 ResponseCodeToStatus(response_code), 1047 NUM_RESPONSE_STATUSES); 1048 1049 bool upload_succeeded = response_code == 200; 1050 1051 // Provide boolean for error recovery (allow us to ignore response_code). 1052 bool discard_log = false; 1053 const size_t log_size = log_manager_.staged_log().length(); 1054 if (upload_succeeded) { 1055 UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024); 1056 } else if (log_size > kUploadLogAvoidRetransmitSize) { 1057 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded", 1058 static_cast<int>(log_size)); 1059 discard_log = true; 1060 } else if (response_code == 400) { 1061 // Bad syntax. Retransmission won't work. 1062 discard_log = true; 1063 } 1064 1065 if (upload_succeeded || discard_log) { 1066 log_manager_.DiscardStagedLog(); 1067 // Store the updated list to disk now that the removed log is uploaded. 1068 log_manager_.PersistUnsentLogs(); 1069 } 1070 1071 if (!log_manager_.has_staged_log()) { 1072 switch (state_) { 1073 case SENDING_INITIAL_STABILITY_LOG: 1074 PrepareInitialMetricsLog(); 1075 SendStagedLog(); 1076 state_ = SENDING_INITIAL_METRICS_LOG; 1077 break; 1078 1079 case SENDING_INITIAL_METRICS_LOG: 1080 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS 1081 : SENDING_CURRENT_LOGS; 1082 break; 1083 1084 case SENDING_OLD_LOGS: 1085 if (!log_manager_.has_unsent_logs()) 1086 state_ = SENDING_CURRENT_LOGS; 1087 break; 1088 1089 case SENDING_CURRENT_LOGS: 1090 break; 1091 1092 default: 1093 NOTREACHED(); 1094 break; 1095 } 1096 1097 if (log_manager_.has_unsent_logs()) 1098 DCHECK_LT(state_, SENDING_CURRENT_LOGS); 1099 } 1100 1101 // Error 400 indicates a problem with the log, not with the server, so 1102 // don't consider that a sign that the server is in trouble. 1103 bool server_is_healthy = upload_succeeded || response_code == 400; 1104 // Don't notify the scheduler that the upload is finished if we've only sent 1105 // the initial stability log, but not yet the initial metrics log (treat the 1106 // two as a single unit of work as far as the scheduler is concerned). 1107 if (state_ != SENDING_INITIAL_METRICS_LOG) { 1108 scheduler_->UploadFinished(server_is_healthy, 1109 log_manager_.has_unsent_logs()); 1110 } 1111 1112 if (server_is_healthy) 1113 client_->OnLogUploadComplete(); 1114 } 1115 1116 void MetricsService::IncrementPrefValue(const char* path) { 1117 int value = local_state_->GetInteger(path); 1118 local_state_->SetInteger(path, value + 1); 1119 } 1120 1121 void MetricsService::IncrementLongPrefsValue(const char* path) { 1122 int64 value = local_state_->GetInt64(path); 1123 local_state_->SetInt64(path, value + 1); 1124 } 1125 1126 bool MetricsService::UmaMetricsProperlyShutdown() { 1127 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN || 1128 clean_shutdown_status_ == NEED_TO_SHUTDOWN); 1129 return clean_shutdown_status_ == CLEANLY_SHUTDOWN; 1130 } 1131 1132 void MetricsService::RegisterSyntheticFieldTrial( 1133 const SyntheticTrialGroup& trial) { 1134 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) { 1135 if (synthetic_trial_groups_[i].id.name == trial.id.name) { 1136 if (synthetic_trial_groups_[i].id.group != trial.id.group) { 1137 synthetic_trial_groups_[i].id.group = trial.id.group; 1138 synthetic_trial_groups_[i].start_time = base::TimeTicks::Now(); 1139 } 1140 return; 1141 } 1142 } 1143 1144 SyntheticTrialGroup trial_group = trial; 1145 trial_group.start_time = base::TimeTicks::Now(); 1146 synthetic_trial_groups_.push_back(trial_group); 1147 } 1148 1149 void MetricsService::RegisterMetricsProvider( 1150 scoped_ptr<metrics::MetricsProvider> provider) { 1151 DCHECK_EQ(INITIALIZED, state_); 1152 metrics_providers_.push_back(provider.release()); 1153 } 1154 1155 void MetricsService::CheckForClonedInstall( 1156 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 1157 state_manager_->CheckForClonedInstall(task_runner); 1158 } 1159 1160 void MetricsService::GetCurrentSyntheticFieldTrials( 1161 std::vector<variations::ActiveGroupId>* synthetic_trials) { 1162 DCHECK(synthetic_trials); 1163 synthetic_trials->clear(); 1164 const MetricsLog* current_log = log_manager_.current_log(); 1165 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) { 1166 if (synthetic_trial_groups_[i].start_time <= current_log->creation_time()) 1167 synthetic_trials->push_back(synthetic_trial_groups_[i].id); 1168 } 1169 } 1170 1171 scoped_ptr<MetricsLog> MetricsService::CreateLog(MetricsLog::LogType log_type) { 1172 return make_scoped_ptr(new MetricsLog(state_manager_->client_id(), 1173 session_id_, 1174 log_type, 1175 client_, 1176 local_state_)); 1177 } 1178 1179 void MetricsService::RecordCurrentHistograms() { 1180 DCHECK(log_manager_.current_log()); 1181 histogram_snapshot_manager_.PrepareDeltas( 1182 base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag); 1183 } 1184 1185 void MetricsService::RecordCurrentStabilityHistograms() { 1186 DCHECK(log_manager_.current_log()); 1187 histogram_snapshot_manager_.PrepareDeltas( 1188 base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag); 1189 } 1190 1191 void MetricsService::LogCleanShutdown() { 1192 // Redundant hack to write pref ASAP. 1193 MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_); 1194 1195 // Redundant setting to assure that we always reset this value at shutdown 1196 // (and that we don't use some alternate path, and not call LogCleanShutdown). 1197 clean_shutdown_status_ = CLEANLY_SHUTDOWN; 1198 1199 clean_exit_beacon_.WriteBeaconValue(true); 1200 RecordCurrentState(local_state_); 1201 local_state_->SetInteger(metrics::prefs::kStabilityExecutionPhase, 1202 MetricsService::SHUTDOWN_COMPLETE); 1203 } 1204 1205 bool MetricsService::ShouldLogEvents() { 1206 // We simply don't log events to UMA if there is a single incognito 1207 // session visible. The problem is that we always notify using the orginal 1208 // profile in order to simplify notification processing. 1209 return !client_->IsOffTheRecordSessionActive(); 1210 } 1211 1212 void MetricsService::RecordBooleanPrefValue(const char* path, bool value) { 1213 DCHECK(IsSingleThreaded()); 1214 local_state_->SetBoolean(path, value); 1215 RecordCurrentState(local_state_); 1216 } 1217 1218 void MetricsService::RecordCurrentState(PrefService* pref) { 1219 pref->SetInt64(metrics::prefs::kStabilityLastTimestampSec, 1220 base::Time::Now().ToTimeT()); 1221 } 1222 1223 } // namespace metrics 1224