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/tracked_objects.h" 183 #include "base/values.h" 184 #include "components/metrics/metrics_log.h" 185 #include "components/metrics/metrics_log_manager.h" 186 #include "components/metrics/metrics_log_uploader.h" 187 #include "components/metrics/metrics_pref_names.h" 188 #include "components/metrics/metrics_reporting_scheduler.h" 189 #include "components/metrics/metrics_service_client.h" 190 #include "components/metrics/metrics_state_manager.h" 191 #include "components/variations/entropy_provider.h" 192 193 using base::Time; 194 using metrics::MetricsLogManager; 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(PrefService* local_state) { 258 local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true); 259 local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase, 260 MetricsService::SHUTDOWN_COMPLETE); 261 // Start writing right away (write happens on a different thread). 262 local_state->CommitPendingWrite(); 263 } 264 265 } // namespace 266 267 268 SyntheticTrialGroup::SyntheticTrialGroup(uint32 trial, uint32 group) { 269 id.name = trial; 270 id.group = group; 271 } 272 273 SyntheticTrialGroup::~SyntheticTrialGroup() { 274 } 275 276 // static 277 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ = 278 MetricsService::CLEANLY_SHUTDOWN; 279 280 MetricsService::ExecutionPhase MetricsService::execution_phase_ = 281 MetricsService::UNINITIALIZED_PHASE; 282 283 // static 284 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) { 285 DCHECK(IsSingleThreaded()); 286 metrics::MetricsStateManager::RegisterPrefs(registry); 287 MetricsLog::RegisterPrefs(registry); 288 289 registry->RegisterInt64Pref(metrics::prefs::kStabilityLaunchTimeSec, 0); 290 registry->RegisterInt64Pref(metrics::prefs::kStabilityLastTimestampSec, 0); 291 registry->RegisterStringPref(metrics::prefs::kStabilityStatsVersion, 292 std::string()); 293 registry->RegisterInt64Pref(metrics::prefs::kStabilityStatsBuildTime, 0); 294 registry->RegisterBooleanPref(metrics::prefs::kStabilityExitedCleanly, true); 295 registry->RegisterIntegerPref(metrics::prefs::kStabilityExecutionPhase, 296 UNINITIALIZED_PHASE); 297 registry->RegisterBooleanPref(metrics::prefs::kStabilitySessionEndCompleted, 298 true); 299 registry->RegisterIntegerPref(metrics::prefs::kMetricsSessionID, -1); 300 301 registry->RegisterListPref(metrics::prefs::kMetricsInitialLogs); 302 registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogs); 303 registry->RegisterListPref(metrics::prefs::kMetricsInitialLogsOld); 304 registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogsOld); 305 306 registry->RegisterInt64Pref(metrics::prefs::kUninstallLaunchCount, 0); 307 registry->RegisterInt64Pref(metrics::prefs::kUninstallMetricsUptimeSec, 0); 308 } 309 310 MetricsService::MetricsService(metrics::MetricsStateManager* state_manager, 311 metrics::MetricsServiceClient* client, 312 PrefService* local_state) 313 : log_manager_(local_state, kUploadLogAvoidRetransmitSize), 314 histogram_snapshot_manager_(this), 315 state_manager_(state_manager), 316 client_(client), 317 local_state_(local_state), 318 recording_active_(false), 319 reporting_active_(false), 320 test_mode_active_(false), 321 state_(INITIALIZED), 322 has_initial_stability_log_(false), 323 log_upload_in_progress_(false), 324 idle_since_last_transmission_(false), 325 session_id_(-1), 326 self_ptr_factory_(this), 327 state_saver_factory_(this) { 328 DCHECK(IsSingleThreaded()); 329 DCHECK(state_manager_); 330 DCHECK(client_); 331 DCHECK(local_state_); 332 } 333 334 MetricsService::~MetricsService() { 335 DisableRecording(); 336 } 337 338 void MetricsService::InitializeMetricsRecordingState() { 339 InitializeMetricsState(); 340 341 base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload, 342 self_ptr_factory_.GetWeakPtr()); 343 scheduler_.reset(new MetricsReportingScheduler(callback)); 344 } 345 346 void MetricsService::Start() { 347 HandleIdleSinceLastTransmission(false); 348 EnableRecording(); 349 EnableReporting(); 350 } 351 352 bool MetricsService::StartIfMetricsReportingEnabled() { 353 const bool enabled = state_manager_->IsMetricsReportingEnabled(); 354 if (enabled) 355 Start(); 356 return enabled; 357 } 358 359 void MetricsService::StartRecordingForTests() { 360 test_mode_active_ = true; 361 EnableRecording(); 362 DisableReporting(); 363 } 364 365 void MetricsService::Stop() { 366 HandleIdleSinceLastTransmission(false); 367 DisableReporting(); 368 DisableRecording(); 369 } 370 371 void MetricsService::EnableReporting() { 372 if (reporting_active_) 373 return; 374 reporting_active_ = true; 375 StartSchedulerIfNecessary(); 376 } 377 378 void MetricsService::DisableReporting() { 379 reporting_active_ = false; 380 } 381 382 std::string MetricsService::GetClientId() { 383 return state_manager_->client_id(); 384 } 385 386 scoped_ptr<const base::FieldTrial::EntropyProvider> 387 MetricsService::CreateEntropyProvider() { 388 // TODO(asvitkine): Refactor the code so that MetricsService does not expose 389 // this method. 390 return state_manager_->CreateEntropyProvider(); 391 } 392 393 void MetricsService::EnableRecording() { 394 DCHECK(IsSingleThreaded()); 395 396 if (recording_active_) 397 return; 398 recording_active_ = true; 399 400 state_manager_->ForceClientIdCreation(); 401 client_->SetClientID(state_manager_->client_id()); 402 if (!log_manager_.current_log()) 403 OpenNewLog(); 404 405 for (size_t i = 0; i < metrics_providers_.size(); ++i) 406 metrics_providers_[i]->OnRecordingEnabled(); 407 408 base::RemoveActionCallback(action_callback_); 409 action_callback_ = base::Bind(&MetricsService::OnUserAction, 410 base::Unretained(this)); 411 base::AddActionCallback(action_callback_); 412 } 413 414 void MetricsService::DisableRecording() { 415 DCHECK(IsSingleThreaded()); 416 417 if (!recording_active_) 418 return; 419 recording_active_ = false; 420 421 base::RemoveActionCallback(action_callback_); 422 423 for (size_t i = 0; i < metrics_providers_.size(); ++i) 424 metrics_providers_[i]->OnRecordingDisabled(); 425 426 PushPendingLogsToPersistentStorage(); 427 DCHECK(!log_manager_.has_staged_log()); 428 } 429 430 bool MetricsService::recording_active() const { 431 DCHECK(IsSingleThreaded()); 432 return recording_active_; 433 } 434 435 bool MetricsService::reporting_active() const { 436 DCHECK(IsSingleThreaded()); 437 return reporting_active_; 438 } 439 440 void MetricsService::RecordDelta(const base::HistogramBase& histogram, 441 const base::HistogramSamples& snapshot) { 442 log_manager_.current_log()->RecordHistogramDelta(histogram.histogram_name(), 443 snapshot); 444 } 445 446 void MetricsService::InconsistencyDetected( 447 base::HistogramBase::Inconsistency problem) { 448 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowser", 449 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE); 450 } 451 452 void MetricsService::UniqueInconsistencyDetected( 453 base::HistogramBase::Inconsistency problem) { 454 UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesBrowserUnique", 455 problem, base::HistogramBase::NEVER_EXCEEDED_VALUE); 456 } 457 458 void MetricsService::InconsistencyDetectedInLoggedCount(int amount) { 459 UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotBrowser", 460 std::abs(amount)); 461 } 462 463 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) { 464 // If there wasn't a lot of action, maybe the computer was asleep, in which 465 // case, the log transmissions should have stopped. Here we start them up 466 // again. 467 if (!in_idle && idle_since_last_transmission_) 468 StartSchedulerIfNecessary(); 469 idle_since_last_transmission_ = in_idle; 470 } 471 472 void MetricsService::OnApplicationNotIdle() { 473 if (recording_active_) 474 HandleIdleSinceLastTransmission(false); 475 } 476 477 void MetricsService::RecordStartOfSessionEnd() { 478 LogCleanShutdown(); 479 RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, false); 480 } 481 482 void MetricsService::RecordCompletedSessionEnd() { 483 LogCleanShutdown(); 484 RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, true); 485 } 486 487 #if defined(OS_ANDROID) || defined(OS_IOS) 488 void MetricsService::OnAppEnterBackground() { 489 scheduler_->Stop(); 490 491 MarkAppCleanShutdownAndCommit(local_state_); 492 493 // At this point, there's no way of knowing when the process will be 494 // killed, so this has to be treated similar to a shutdown, closing and 495 // persisting all logs. Unlinke a shutdown, the state is primed to be ready 496 // to continue logging and uploading if the process does return. 497 if (recording_active() && state_ >= SENDING_INITIAL_STABILITY_LOG) { 498 PushPendingLogsToPersistentStorage(); 499 // Persisting logs closes the current log, so start recording a new log 500 // immediately to capture any background work that might be done before the 501 // process is killed. 502 OpenNewLog(); 503 } 504 } 505 506 void MetricsService::OnAppEnterForeground() { 507 local_state_->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false); 508 StartSchedulerIfNecessary(); 509 } 510 #else 511 void MetricsService::LogNeedForCleanShutdown(PrefService* local_state) { 512 local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false); 513 // Redundant setting to be sure we call for a clean shutdown. 514 clean_shutdown_status_ = NEED_TO_SHUTDOWN; 515 } 516 #endif // defined(OS_ANDROID) || defined(OS_IOS) 517 518 // static 519 void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase, 520 PrefService* local_state) { 521 execution_phase_ = execution_phase; 522 local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase, 523 execution_phase_); 524 } 525 526 void MetricsService::RecordBreakpadRegistration(bool success) { 527 if (!success) 528 IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationFail); 529 else 530 IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationSuccess); 531 } 532 533 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) { 534 if (!has_debugger) 535 IncrementPrefValue(metrics::prefs::kStabilityDebuggerNotPresent); 536 else 537 IncrementPrefValue(metrics::prefs::kStabilityDebuggerPresent); 538 } 539 540 //------------------------------------------------------------------------------ 541 // private methods 542 //------------------------------------------------------------------------------ 543 544 545 //------------------------------------------------------------------------------ 546 // Initialization methods 547 548 void MetricsService::InitializeMetricsState() { 549 local_state_->SetString(metrics::prefs::kStabilityStatsVersion, 550 client_->GetVersionString()); 551 local_state_->SetInt64(metrics::prefs::kStabilityStatsBuildTime, 552 MetricsLog::GetBuildTime()); 553 554 session_id_ = local_state_->GetInteger(metrics::prefs::kMetricsSessionID); 555 556 if (!local_state_->GetBoolean(metrics::prefs::kStabilityExitedCleanly)) { 557 IncrementPrefValue(metrics::prefs::kStabilityCrashCount); 558 // Reset flag, and wait until we call LogNeedForCleanShutdown() before 559 // monitoring. 560 local_state_->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true); 561 562 // TODO(rtenneti): On windows, consider saving/getting execution_phase from 563 // the registry. 564 int execution_phase = 565 local_state_->GetInteger(metrics::prefs::kStabilityExecutionPhase); 566 UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase", 567 execution_phase); 568 569 // If the previous session didn't exit cleanly, then prepare an initial 570 // stability log if UMA is enabled. 571 if (state_manager_->IsMetricsReportingEnabled()) 572 PrepareInitialStabilityLog(); 573 } 574 575 // Update session ID. 576 ++session_id_; 577 local_state_->SetInteger(metrics::prefs::kMetricsSessionID, session_id_); 578 579 // Stability bookkeeping 580 IncrementPrefValue(metrics::prefs::kStabilityLaunchCount); 581 582 DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_); 583 SetExecutionPhase(START_METRICS_RECORDING, local_state_); 584 585 if (!local_state_->GetBoolean( 586 metrics::prefs::kStabilitySessionEndCompleted)) { 587 IncrementPrefValue(metrics::prefs::kStabilityIncompleteSessionEndCount); 588 // This is marked false when we get a WM_ENDSESSION. 589 local_state_->SetBoolean(metrics::prefs::kStabilitySessionEndCompleted, 590 true); 591 } 592 593 // Call GetUptimes() for the first time, thus allowing all later calls 594 // to record incremental uptimes accurately. 595 base::TimeDelta ignored_uptime_parameter; 596 base::TimeDelta startup_uptime; 597 GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter); 598 DCHECK_EQ(0, startup_uptime.InMicroseconds()); 599 // For backwards compatibility, leave this intact in case Omaha is checking 600 // them. metrics::prefs::kStabilityLastTimestampSec may also be useless now. 601 // TODO(jar): Delete these if they have no uses. 602 local_state_->SetInt64(metrics::prefs::kStabilityLaunchTimeSec, 603 Time::Now().ToTimeT()); 604 605 // Bookkeeping for the uninstall metrics. 606 IncrementLongPrefsValue(metrics::prefs::kUninstallLaunchCount); 607 608 // Kick off the process of saving the state (so the uptime numbers keep 609 // getting updated) every n minutes. 610 ScheduleNextStateSave(); 611 } 612 613 void MetricsService::OnUserAction(const std::string& action) { 614 if (!ShouldLogEvents()) 615 return; 616 617 log_manager_.current_log()->RecordUserAction(action); 618 HandleIdleSinceLastTransmission(false); 619 } 620 621 void MetricsService::FinishedGatheringInitialMetrics() { 622 DCHECK_EQ(INIT_TASK_SCHEDULED, state_); 623 state_ = INIT_TASK_DONE; 624 625 // Create the initial log. 626 if (!initial_metrics_log_.get()) { 627 initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG); 628 NotifyOnDidCreateMetricsLog(); 629 } 630 631 scheduler_->InitTaskComplete(); 632 } 633 634 void MetricsService::GetUptimes(PrefService* pref, 635 base::TimeDelta* incremental_uptime, 636 base::TimeDelta* uptime) { 637 base::TimeTicks now = base::TimeTicks::Now(); 638 // If this is the first call, init |first_updated_time_| and 639 // |last_updated_time_|. 640 if (last_updated_time_.is_null()) { 641 first_updated_time_ = now; 642 last_updated_time_ = now; 643 } 644 *incremental_uptime = now - last_updated_time_; 645 *uptime = now - first_updated_time_; 646 last_updated_time_ = now; 647 648 const int64 incremental_time_secs = incremental_uptime->InSeconds(); 649 if (incremental_time_secs > 0) { 650 int64 metrics_uptime = 651 pref->GetInt64(metrics::prefs::kUninstallMetricsUptimeSec); 652 metrics_uptime += incremental_time_secs; 653 pref->SetInt64(metrics::prefs::kUninstallMetricsUptimeSec, metrics_uptime); 654 } 655 } 656 657 void MetricsService::AddObserver(MetricsServiceObserver* observer) { 658 DCHECK(thread_checker_.CalledOnValidThread()); 659 observers_.AddObserver(observer); 660 } 661 662 void MetricsService::RemoveObserver(MetricsServiceObserver* observer) { 663 DCHECK(thread_checker_.CalledOnValidThread()); 664 observers_.RemoveObserver(observer); 665 } 666 667 void MetricsService::NotifyOnDidCreateMetricsLog() { 668 DCHECK(thread_checker_.CalledOnValidThread()); 669 FOR_EACH_OBSERVER( 670 MetricsServiceObserver, observers_, OnDidCreateMetricsLog()); 671 for (size_t i = 0; i < metrics_providers_.size(); ++i) 672 metrics_providers_[i]->OnDidCreateMetricsLog(); 673 } 674 675 //------------------------------------------------------------------------------ 676 // State save methods 677 678 void MetricsService::ScheduleNextStateSave() { 679 state_saver_factory_.InvalidateWeakPtrs(); 680 681 base::MessageLoop::current()->PostDelayedTask(FROM_HERE, 682 base::Bind(&MetricsService::SaveLocalState, 683 state_saver_factory_.GetWeakPtr()), 684 base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes)); 685 } 686 687 void MetricsService::SaveLocalState() { 688 RecordCurrentState(local_state_); 689 690 // TODO(jar):110021 Does this run down the batteries???? 691 ScheduleNextStateSave(); 692 } 693 694 695 //------------------------------------------------------------------------------ 696 // Recording control methods 697 698 void MetricsService::OpenNewLog() { 699 DCHECK(!log_manager_.current_log()); 700 701 log_manager_.BeginLoggingWithLog(CreateLog(MetricsLog::ONGOING_LOG)); 702 NotifyOnDidCreateMetricsLog(); 703 if (state_ == INITIALIZED) { 704 // We only need to schedule that run once. 705 state_ = INIT_TASK_SCHEDULED; 706 707 base::MessageLoop::current()->PostDelayedTask( 708 FROM_HERE, 709 base::Bind(&MetricsService::StartGatheringMetrics, 710 self_ptr_factory_.GetWeakPtr()), 711 base::TimeDelta::FromSeconds(kInitializationDelaySeconds)); 712 } 713 } 714 715 void MetricsService::StartGatheringMetrics() { 716 client_->StartGatheringMetrics( 717 base::Bind(&MetricsService::FinishedGatheringInitialMetrics, 718 self_ptr_factory_.GetWeakPtr())); 719 } 720 721 void MetricsService::CloseCurrentLog() { 722 if (!log_manager_.current_log()) 723 return; 724 725 // TODO(jar): Integrate bounds on log recording more consistently, so that we 726 // can stop recording logs that are too big much sooner. 727 if (log_manager_.current_log()->num_events() > kEventLimit) { 728 UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events", 729 log_manager_.current_log()->num_events()); 730 log_manager_.DiscardCurrentLog(); 731 OpenNewLog(); // Start trivial log to hold our histograms. 732 } 733 734 // Put incremental data (histogram deltas, and realtime stats deltas) at the 735 // end of all log transmissions (initial log handles this separately). 736 // RecordIncrementalStabilityElements only exists on the derived 737 // MetricsLog class. 738 MetricsLog* current_log = 739 static_cast<MetricsLog*>(log_manager_.current_log()); 740 DCHECK(current_log); 741 std::vector<variations::ActiveGroupId> synthetic_trials; 742 GetCurrentSyntheticFieldTrials(&synthetic_trials); 743 current_log->RecordEnvironment(metrics_providers_.get(), synthetic_trials); 744 base::TimeDelta incremental_uptime; 745 base::TimeDelta uptime; 746 GetUptimes(local_state_, &incremental_uptime, &uptime); 747 current_log->RecordStabilityMetrics(metrics_providers_.get(), 748 incremental_uptime, uptime); 749 750 RecordCurrentHistograms(); 751 current_log->RecordGeneralMetrics(metrics_providers_.get()); 752 753 log_manager_.FinishCurrentLog(); 754 } 755 756 void MetricsService::PushPendingLogsToPersistentStorage() { 757 if (state_ < SENDING_INITIAL_STABILITY_LOG) 758 return; // We didn't and still don't have time to get plugin list etc. 759 760 if (log_manager_.has_staged_log()) { 761 // We may race here, and send second copy of the log later. 762 metrics::PersistedLogs::StoreType store_type; 763 if (log_upload_in_progress_) 764 store_type = metrics::PersistedLogs::PROVISIONAL_STORE; 765 else 766 store_type = metrics::PersistedLogs::NORMAL_STORE; 767 log_manager_.StoreStagedLogAsUnsent(store_type); 768 } 769 DCHECK(!log_manager_.has_staged_log()); 770 CloseCurrentLog(); 771 log_manager_.PersistUnsentLogs(); 772 773 // If there was a staged and/or current log, then there is now at least one 774 // log waiting to be uploaded. 775 if (log_manager_.has_unsent_logs()) 776 state_ = SENDING_OLD_LOGS; 777 } 778 779 //------------------------------------------------------------------------------ 780 // Transmission of logs methods 781 782 void MetricsService::StartSchedulerIfNecessary() { 783 // Never schedule cutting or uploading of logs in test mode. 784 if (test_mode_active_) 785 return; 786 787 // Even if reporting is disabled, the scheduler is needed to trigger the 788 // creation of the initial log, which must be done in order for any logs to be 789 // persisted on shutdown or backgrounding. 790 if (recording_active() && 791 (reporting_active() || state_ < SENDING_INITIAL_STABILITY_LOG)) { 792 scheduler_->Start(); 793 } 794 } 795 796 void MetricsService::StartScheduledUpload() { 797 // If we're getting no notifications, then the log won't have much in it, and 798 // it's possible the computer is about to go to sleep, so don't upload and 799 // stop the scheduler. 800 // If recording has been turned off, the scheduler doesn't need to run. 801 // If reporting is off, proceed if the initial log hasn't been created, since 802 // that has to happen in order for logs to be cut and stored when persisting. 803 // TODO(stuartmorgan): Call Stop() on the scheduler when reporting and/or 804 // recording are turned off instead of letting it fire and then aborting. 805 if (idle_since_last_transmission_ || 806 !recording_active() || 807 (!reporting_active() && state_ >= SENDING_INITIAL_STABILITY_LOG)) { 808 scheduler_->Stop(); 809 scheduler_->UploadCancelled(); 810 return; 811 } 812 813 // If the callback was to upload an old log, but there no longer is one, 814 // just report success back to the scheduler to begin the ongoing log 815 // callbacks. 816 // TODO(stuartmorgan): Consider removing the distinction between 817 // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine 818 // now that the log upload flow is the same for both modes. 819 if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) { 820 state_ = SENDING_CURRENT_LOGS; 821 scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */); 822 return; 823 } 824 // If there are unsent logs, send the next one. If not, start the asynchronous 825 // process of finalizing the current log for upload. 826 if (state_ == SENDING_OLD_LOGS) { 827 DCHECK(log_manager_.has_unsent_logs()); 828 log_manager_.StageNextLogForUpload(); 829 SendStagedLog(); 830 } else { 831 client_->CollectFinalMetrics( 832 base::Bind(&MetricsService::OnFinalLogInfoCollectionDone, 833 self_ptr_factory_.GetWeakPtr())); 834 } 835 } 836 837 void MetricsService::OnFinalLogInfoCollectionDone() { 838 // If somehow there is a log upload in progress, we return and hope things 839 // work out. The scheduler isn't informed since if this happens, the scheduler 840 // will get a response from the upload. 841 DCHECK(!log_upload_in_progress_); 842 if (log_upload_in_progress_) 843 return; 844 845 // Abort if metrics were turned off during the final info gathering. 846 if (!recording_active()) { 847 scheduler_->Stop(); 848 scheduler_->UploadCancelled(); 849 return; 850 } 851 852 StageNewLog(); 853 854 // If logs shouldn't be uploaded, stop here. It's important that this check 855 // be after StageNewLog(), otherwise the previous logs will never be loaded, 856 // and thus the open log won't be persisted. 857 // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading 858 // of previous logs to not require running part of the upload logic. 859 // http://crbug.com/157337 860 if (!reporting_active()) { 861 scheduler_->Stop(); 862 scheduler_->UploadCancelled(); 863 return; 864 } 865 866 SendStagedLog(); 867 } 868 869 void MetricsService::StageNewLog() { 870 if (log_manager_.has_staged_log()) 871 return; 872 873 switch (state_) { 874 case INITIALIZED: 875 case INIT_TASK_SCHEDULED: // We should be further along by now. 876 NOTREACHED(); 877 return; 878 879 case INIT_TASK_DONE: 880 if (has_initial_stability_log_) { 881 // There's an initial stability log, ready to send. 882 log_manager_.StageNextLogForUpload(); 883 has_initial_stability_log_ = false; 884 // Note: No need to call LoadPersistedUnsentLogs() here because unsent 885 // logs have already been loaded by PrepareInitialStabilityLog(). 886 state_ = SENDING_INITIAL_STABILITY_LOG; 887 } else { 888 PrepareInitialMetricsLog(); 889 // Load unsent logs (if any) from local state. 890 log_manager_.LoadPersistedUnsentLogs(); 891 state_ = SENDING_INITIAL_METRICS_LOG; 892 } 893 break; 894 895 case SENDING_OLD_LOGS: 896 NOTREACHED(); // Shouldn't be staging a new log during old log sending. 897 return; 898 899 case SENDING_CURRENT_LOGS: 900 CloseCurrentLog(); 901 OpenNewLog(); 902 log_manager_.StageNextLogForUpload(); 903 break; 904 905 default: 906 NOTREACHED(); 907 return; 908 } 909 910 DCHECK(log_manager_.has_staged_log()); 911 } 912 913 void MetricsService::PrepareInitialStabilityLog() { 914 DCHECK_EQ(INITIALIZED, state_); 915 DCHECK_NE(0, local_state_->GetInteger(metrics::prefs::kStabilityCrashCount)); 916 917 scoped_ptr<MetricsLog> initial_stability_log( 918 CreateLog(MetricsLog::INITIAL_STABILITY_LOG)); 919 920 // Do not call NotifyOnDidCreateMetricsLog here because the stability 921 // log describes stats from the _previous_ session. 922 923 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs()) 924 return; 925 926 log_manager_.LoadPersistedUnsentLogs(); 927 928 log_manager_.PauseCurrentLog(); 929 log_manager_.BeginLoggingWithLog(initial_stability_log.Pass()); 930 931 // Note: Some stability providers may record stability stats via histograms, 932 // so this call has to be after BeginLoggingWithLog(). 933 log_manager_.current_log()->RecordStabilityMetrics( 934 metrics_providers_.get(), base::TimeDelta(), base::TimeDelta()); 935 RecordCurrentStabilityHistograms(); 936 937 // Note: RecordGeneralMetrics() intentionally not called since this log is for 938 // stability stats from a previous session only. 939 940 log_manager_.FinishCurrentLog(); 941 log_manager_.ResumePausedLog(); 942 943 // Store unsent logs, including the stability log that was just saved, so 944 // that they're not lost in case of a crash before upload time. 945 log_manager_.PersistUnsentLogs(); 946 947 has_initial_stability_log_ = true; 948 } 949 950 void MetricsService::PrepareInitialMetricsLog() { 951 DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG); 952 953 std::vector<variations::ActiveGroupId> synthetic_trials; 954 GetCurrentSyntheticFieldTrials(&synthetic_trials); 955 initial_metrics_log_->RecordEnvironment(metrics_providers_.get(), 956 synthetic_trials); 957 base::TimeDelta incremental_uptime; 958 base::TimeDelta uptime; 959 GetUptimes(local_state_, &incremental_uptime, &uptime); 960 961 // Histograms only get written to the current log, so make the new log current 962 // before writing them. 963 log_manager_.PauseCurrentLog(); 964 log_manager_.BeginLoggingWithLog(initial_metrics_log_.Pass()); 965 966 // Note: Some stability providers may record stability stats via histograms, 967 // so this call has to be after BeginLoggingWithLog(). 968 MetricsLog* current_log = 969 static_cast<MetricsLog*>(log_manager_.current_log()); 970 current_log->RecordStabilityMetrics(metrics_providers_.get(), 971 base::TimeDelta(), base::TimeDelta()); 972 RecordCurrentHistograms(); 973 974 current_log->RecordGeneralMetrics(metrics_providers_.get()); 975 976 log_manager_.FinishCurrentLog(); 977 log_manager_.ResumePausedLog(); 978 979 DCHECK(!log_manager_.has_staged_log()); 980 log_manager_.StageNextLogForUpload(); 981 } 982 983 void MetricsService::SendStagedLog() { 984 DCHECK(log_manager_.has_staged_log()); 985 if (!log_manager_.has_staged_log()) 986 return; 987 988 DCHECK(!log_upload_in_progress_); 989 log_upload_in_progress_ = true; 990 991 if (!log_uploader_) { 992 log_uploader_ = client_->CreateUploader( 993 kServerUrl, kMimeType, 994 base::Bind(&MetricsService::OnLogUploadComplete, 995 self_ptr_factory_.GetWeakPtr())); 996 } 997 998 const std::string hash = 999 base::HexEncode(log_manager_.staged_log_hash().data(), 1000 log_manager_.staged_log_hash().size()); 1001 bool success = log_uploader_->UploadLog(log_manager_.staged_log(), hash); 1002 UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", success); 1003 if (!success) { 1004 // Skip this upload and hope things work out next time. 1005 log_manager_.DiscardStagedLog(); 1006 scheduler_->UploadCancelled(); 1007 log_upload_in_progress_ = false; 1008 return; 1009 } 1010 1011 HandleIdleSinceLastTransmission(true); 1012 } 1013 1014 1015 void MetricsService::OnLogUploadComplete(int response_code) { 1016 DCHECK(log_upload_in_progress_); 1017 log_upload_in_progress_ = false; 1018 1019 // Log a histogram to track response success vs. failure rates. 1020 UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf", 1021 ResponseCodeToStatus(response_code), 1022 NUM_RESPONSE_STATUSES); 1023 1024 // If the upload was provisionally stored, drop it now that the upload is 1025 // known to have gone through. 1026 log_manager_.DiscardLastProvisionalStore(); 1027 1028 bool upload_succeeded = response_code == 200; 1029 1030 // Provide boolean for error recovery (allow us to ignore response_code). 1031 bool discard_log = false; 1032 const size_t log_size = log_manager_.staged_log().length(); 1033 if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) { 1034 UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded", 1035 static_cast<int>(log_size)); 1036 discard_log = true; 1037 } else if (response_code == 400) { 1038 // Bad syntax. Retransmission won't work. 1039 discard_log = true; 1040 } 1041 1042 if (upload_succeeded || discard_log) 1043 log_manager_.DiscardStagedLog(); 1044 1045 if (!log_manager_.has_staged_log()) { 1046 switch (state_) { 1047 case SENDING_INITIAL_STABILITY_LOG: 1048 // Store the updated list to disk now that the removed log is uploaded. 1049 log_manager_.PersistUnsentLogs(); 1050 PrepareInitialMetricsLog(); 1051 SendStagedLog(); 1052 state_ = SENDING_INITIAL_METRICS_LOG; 1053 break; 1054 1055 case SENDING_INITIAL_METRICS_LOG: 1056 // The initial metrics log never gets persisted to local state, so it's 1057 // not necessary to call log_manager_.PersistUnsentLogs() here. 1058 // TODO(asvitkine): It should be persisted like the initial stability 1059 // log and old unsent logs. http://crbug.com/328417 1060 state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS 1061 : SENDING_CURRENT_LOGS; 1062 break; 1063 1064 case SENDING_OLD_LOGS: 1065 // Store the updated list to disk now that the removed log is uploaded. 1066 log_manager_.PersistUnsentLogs(); 1067 if (!log_manager_.has_unsent_logs()) 1068 state_ = SENDING_CURRENT_LOGS; 1069 break; 1070 1071 case SENDING_CURRENT_LOGS: 1072 break; 1073 1074 default: 1075 NOTREACHED(); 1076 break; 1077 } 1078 1079 if (log_manager_.has_unsent_logs()) 1080 DCHECK_LT(state_, SENDING_CURRENT_LOGS); 1081 } 1082 1083 // Error 400 indicates a problem with the log, not with the server, so 1084 // don't consider that a sign that the server is in trouble. 1085 bool server_is_healthy = upload_succeeded || response_code == 400; 1086 // Don't notify the scheduler that the upload is finished if we've only sent 1087 // the initial stability log, but not yet the initial metrics log (treat the 1088 // two as a single unit of work as far as the scheduler is concerned). 1089 if (state_ != SENDING_INITIAL_METRICS_LOG) { 1090 scheduler_->UploadFinished(server_is_healthy, 1091 log_manager_.has_unsent_logs()); 1092 } 1093 1094 if (server_is_healthy) 1095 client_->OnLogUploadComplete(); 1096 } 1097 1098 void MetricsService::IncrementPrefValue(const char* path) { 1099 int value = local_state_->GetInteger(path); 1100 local_state_->SetInteger(path, value + 1); 1101 } 1102 1103 void MetricsService::IncrementLongPrefsValue(const char* path) { 1104 int64 value = local_state_->GetInt64(path); 1105 local_state_->SetInt64(path, value + 1); 1106 } 1107 1108 bool MetricsService::UmaMetricsProperlyShutdown() { 1109 CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN || 1110 clean_shutdown_status_ == NEED_TO_SHUTDOWN); 1111 return clean_shutdown_status_ == CLEANLY_SHUTDOWN; 1112 } 1113 1114 void MetricsService::RegisterSyntheticFieldTrial( 1115 const SyntheticTrialGroup& trial) { 1116 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) { 1117 if (synthetic_trial_groups_[i].id.name == trial.id.name) { 1118 if (synthetic_trial_groups_[i].id.group != trial.id.group) { 1119 synthetic_trial_groups_[i].id.group = trial.id.group; 1120 synthetic_trial_groups_[i].start_time = base::TimeTicks::Now(); 1121 } 1122 return; 1123 } 1124 } 1125 1126 SyntheticTrialGroup trial_group = trial; 1127 trial_group.start_time = base::TimeTicks::Now(); 1128 synthetic_trial_groups_.push_back(trial_group); 1129 } 1130 1131 void MetricsService::RegisterMetricsProvider( 1132 scoped_ptr<metrics::MetricsProvider> provider) { 1133 DCHECK_EQ(INITIALIZED, state_); 1134 metrics_providers_.push_back(provider.release()); 1135 } 1136 1137 void MetricsService::CheckForClonedInstall( 1138 scoped_refptr<base::SingleThreadTaskRunner> task_runner) { 1139 state_manager_->CheckForClonedInstall(task_runner); 1140 } 1141 1142 void MetricsService::GetCurrentSyntheticFieldTrials( 1143 std::vector<variations::ActiveGroupId>* synthetic_trials) { 1144 DCHECK(synthetic_trials); 1145 synthetic_trials->clear(); 1146 const MetricsLog* current_log = 1147 static_cast<const MetricsLog*>(log_manager_.current_log()); 1148 for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) { 1149 if (synthetic_trial_groups_[i].start_time <= current_log->creation_time()) 1150 synthetic_trials->push_back(synthetic_trial_groups_[i].id); 1151 } 1152 } 1153 1154 scoped_ptr<MetricsLog> MetricsService::CreateLog(MetricsLog::LogType log_type) { 1155 return make_scoped_ptr(new MetricsLog(state_manager_->client_id(), 1156 session_id_, 1157 log_type, 1158 client_, 1159 local_state_)); 1160 } 1161 1162 void MetricsService::RecordCurrentHistograms() { 1163 DCHECK(log_manager_.current_log()); 1164 histogram_snapshot_manager_.PrepareDeltas( 1165 base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag); 1166 } 1167 1168 void MetricsService::RecordCurrentStabilityHistograms() { 1169 DCHECK(log_manager_.current_log()); 1170 histogram_snapshot_manager_.PrepareDeltas( 1171 base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag); 1172 } 1173 1174 void MetricsService::LogCleanShutdown() { 1175 // Redundant hack to write pref ASAP. 1176 MarkAppCleanShutdownAndCommit(local_state_); 1177 1178 // Redundant setting to assure that we always reset this value at shutdown 1179 // (and that we don't use some alternate path, and not call LogCleanShutdown). 1180 clean_shutdown_status_ = CLEANLY_SHUTDOWN; 1181 1182 RecordBooleanPrefValue(metrics::prefs::kStabilityExitedCleanly, true); 1183 local_state_->SetInteger(metrics::prefs::kStabilityExecutionPhase, 1184 MetricsService::SHUTDOWN_COMPLETE); 1185 } 1186 1187 bool MetricsService::ShouldLogEvents() { 1188 // We simply don't log events to UMA if there is a single incognito 1189 // session visible. The problem is that we always notify using the orginal 1190 // profile in order to simplify notification processing. 1191 return !client_->IsOffTheRecordSessionActive(); 1192 } 1193 1194 void MetricsService::RecordBooleanPrefValue(const char* path, bool value) { 1195 DCHECK(IsSingleThreaded()); 1196 local_state_->SetBoolean(path, value); 1197 RecordCurrentState(local_state_); 1198 } 1199 1200 void MetricsService::RecordCurrentState(PrefService* pref) { 1201 pref->SetInt64(metrics::prefs::kStabilityLastTimestampSec, 1202 Time::Now().ToTimeT()); 1203 1204 for (size_t i = 0; i < metrics_providers_.size(); ++i) 1205 metrics_providers_[i]->RecordCurrentState(); 1206 } 1207