Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / metrics / metrics_service.cc
index 66ee1ce..adb8f2c 100644 (file)
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
 #include "base/tracked_objects.h"
 #include "base/values.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_state_manager.h"
 #include "components/variations/entropy_provider.h"
 
-using base::Time;
-using metrics::MetricsLogManager;
+namespace metrics {
 
 namespace {
 
@@ -254,9 +254,15 @@ ResponseStatus ResponseCodeToStatus(int response_code) {
   }
 }
 
-void MarkAppCleanShutdownAndCommit(PrefService* local_state) {
-  local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true);
-  local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase,
+bool NewInitialMetricsTimingEnabled() {
+  return base::FieldTrialList::FindFullName("UMAInitialMetricsTiming") ==
+      "Enabled";
+}
+
+void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon,
+                                   PrefService* local_state) {
+  clean_exit_beacon->WriteBeaconValue(true);
+  local_state->SetInteger(prefs::kStabilityExecutionPhase,
                           MetricsService::SHUTDOWN_COMPLETE);
   // Start writing right away (write happens on a different thread).
   local_state->CommitPendingWrite();
@@ -283,38 +289,37 @@ MetricsService::ExecutionPhase MetricsService::execution_phase_ =
 // static
 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
   DCHECK(IsSingleThreaded());
-  metrics::MetricsStateManager::RegisterPrefs(registry);
+  MetricsStateManager::RegisterPrefs(registry);
   MetricsLog::RegisterPrefs(registry);
 
-  registry->RegisterInt64Pref(metrics::prefs::kStabilityLaunchTimeSec, 0);
-  registry->RegisterInt64Pref(metrics::prefs::kStabilityLastTimestampSec, 0);
-  registry->RegisterStringPref(metrics::prefs::kStabilityStatsVersion,
-                               std::string());
-  registry->RegisterInt64Pref(metrics::prefs::kStabilityStatsBuildTime, 0);
-  registry->RegisterBooleanPref(metrics::prefs::kStabilityExitedCleanly, true);
-  registry->RegisterIntegerPref(metrics::prefs::kStabilityExecutionPhase,
+  registry->RegisterInt64Pref(prefs::kInstallDate, 0);
+
+  registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
+  registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
+  registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
+  registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
+  registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
+  registry->RegisterIntegerPref(prefs::kStabilityExecutionPhase,
                                 UNINITIALIZED_PHASE);
-  registry->RegisterBooleanPref(metrics::prefs::kStabilitySessionEndCompleted,
-                                true);
-  registry->RegisterIntegerPref(metrics::prefs::kMetricsSessionID, -1);
+  registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
+  registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
 
-  registry->RegisterListPref(metrics::prefs::kMetricsInitialLogs);
-  registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogs);
-  registry->RegisterListPref(metrics::prefs::kMetricsInitialLogsOld);
-  registry->RegisterListPref(metrics::prefs::kMetricsOngoingLogsOld);
+  registry->RegisterListPref(prefs::kMetricsInitialLogs);
+  registry->RegisterListPref(prefs::kMetricsOngoingLogs);
 
-  registry->RegisterInt64Pref(metrics::prefs::kUninstallLaunchCount, 0);
-  registry->RegisterInt64Pref(metrics::prefs::kUninstallMetricsUptimeSec, 0);
+  registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
+  registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
 }
 
-MetricsService::MetricsService(metrics::MetricsStateManager* state_manager,
-                               metrics::MetricsServiceClient* client,
+MetricsService::MetricsService(MetricsStateManager* state_manager,
+                               MetricsServiceClient* client,
                                PrefService* local_state)
     : log_manager_(local_state, kUploadLogAvoidRetransmitSize),
       histogram_snapshot_manager_(this),
       state_manager_(state_manager),
       client_(client),
       local_state_(local_state),
+      clean_exit_beacon_(client->GetRegistryBackupKey(), local_state),
       recording_active_(false),
       reporting_active_(false),
       test_mode_active_(false),
@@ -329,6 +334,11 @@ MetricsService::MetricsService(metrics::MetricsStateManager* state_manager,
   DCHECK(state_manager_);
   DCHECK(client_);
   DCHECK(local_state_);
+
+  // Set the install date if this is our first run.
+  int64 install_date = local_state_->GetInt64(prefs::kInstallDate);
+  if (install_date == 0)
+    local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
 }
 
 MetricsService::~MetricsService() {
@@ -383,6 +393,10 @@ std::string MetricsService::GetClientId() {
   return state_manager_->client_id();
 }
 
+int64 MetricsService::GetInstallDate() {
+  return local_state_->GetInt64(prefs::kInstallDate);
+}
+
 scoped_ptr<const base::FieldTrial::EntropyProvider>
 MetricsService::CreateEntropyProvider() {
   // TODO(asvitkine): Refactor the code so that MetricsService does not expose
@@ -398,7 +412,7 @@ void MetricsService::EnableRecording() {
   recording_active_ = true;
 
   state_manager_->ForceClientIdCreation();
-  client_->SetClientID(state_manager_->client_id());
+  client_->SetMetricsClientId(state_manager_->client_id());
   if (!log_manager_.current_log())
     OpenNewLog();
 
@@ -424,7 +438,6 @@ void MetricsService::DisableRecording() {
     metrics_providers_[i]->OnRecordingDisabled();
 
   PushPendingLogsToPersistentStorage();
-  DCHECK(!log_manager_.has_staged_log());
 }
 
 bool MetricsService::recording_active() const {
@@ -476,19 +489,19 @@ void MetricsService::OnApplicationNotIdle() {
 
 void MetricsService::RecordStartOfSessionEnd() {
   LogCleanShutdown();
-  RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, false);
+  RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
 }
 
 void MetricsService::RecordCompletedSessionEnd() {
   LogCleanShutdown();
-  RecordBooleanPrefValue(metrics::prefs::kStabilitySessionEndCompleted, true);
+  RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
 }
 
 #if defined(OS_ANDROID) || defined(OS_IOS)
 void MetricsService::OnAppEnterBackground() {
   scheduler_->Stop();
 
-  MarkAppCleanShutdownAndCommit(local_state_);
+  MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
 
   // At this point, there's no way of knowing when the process will be
   // killed, so this has to be treated similar to a shutdown, closing and
@@ -504,12 +517,12 @@ void MetricsService::OnAppEnterBackground() {
 }
 
 void MetricsService::OnAppEnterForeground() {
-  local_state_->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false);
+  clean_exit_beacon_.WriteBeaconValue(false);
   StartSchedulerIfNecessary();
 }
 #else
-void MetricsService::LogNeedForCleanShutdown(PrefService* local_state) {
-  local_state->SetBoolean(metrics::prefs::kStabilityExitedCleanly, false);
+void MetricsService::LogNeedForCleanShutdown() {
+  clean_exit_beacon_.WriteBeaconValue(false);
   // Redundant setting to be sure we call for a clean shutdown.
   clean_shutdown_status_ = NEED_TO_SHUTDOWN;
 }
@@ -519,22 +532,34 @@ void MetricsService::LogNeedForCleanShutdown(PrefService* local_state) {
 void MetricsService::SetExecutionPhase(ExecutionPhase execution_phase,
                                        PrefService* local_state) {
   execution_phase_ = execution_phase;
-  local_state->SetInteger(metrics::prefs::kStabilityExecutionPhase,
-                          execution_phase_);
+  local_state->SetInteger(prefs::kStabilityExecutionPhase, execution_phase_);
 }
 
 void MetricsService::RecordBreakpadRegistration(bool success) {
   if (!success)
-    IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationFail);
+    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
   else
-    IncrementPrefValue(metrics::prefs::kStabilityBreakpadRegistrationSuccess);
+    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
 }
 
 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
   if (!has_debugger)
-    IncrementPrefValue(metrics::prefs::kStabilityDebuggerNotPresent);
+    IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
   else
-    IncrementPrefValue(metrics::prefs::kStabilityDebuggerPresent);
+    IncrementPrefValue(prefs::kStabilityDebuggerPresent);
+}
+
+void MetricsService::ClearSavedStabilityMetrics() {
+  for (size_t i = 0; i < metrics_providers_.size(); ++i)
+    metrics_providers_[i]->ClearSavedStabilityMetrics();
+
+  // Reset the prefs that are managed by MetricsService/MetricsLog directly.
+  local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
+  local_state_->SetInteger(prefs::kStabilityExecutionPhase,
+                           UNINITIALIZED_PHASE);
+  local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+  local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
+  local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
 }
 
 //------------------------------------------------------------------------------
@@ -546,48 +571,65 @@ void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
 // Initialization methods
 
 void MetricsService::InitializeMetricsState() {
-  local_state_->SetString(metrics::prefs::kStabilityStatsVersion,
-                          client_->GetVersionString());
-  local_state_->SetInt64(metrics::prefs::kStabilityStatsBuildTime,
-                         MetricsLog::GetBuildTime());
+  const int64 buildtime = MetricsLog::GetBuildTime();
+  const std::string version = client_->GetVersionString();
+  bool version_changed = false;
+  if (local_state_->GetInt64(prefs::kStabilityStatsBuildTime) != buildtime ||
+      local_state_->GetString(prefs::kStabilityStatsVersion) != version) {
+    local_state_->SetString(prefs::kStabilityStatsVersion, version);
+    local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
+    version_changed = true;
+  }
 
-  session_id_ = local_state_->GetInteger(metrics::prefs::kMetricsSessionID);
+  log_manager_.LoadPersistedUnsentLogs();
 
-  if (!local_state_->GetBoolean(metrics::prefs::kStabilityExitedCleanly)) {
-    IncrementPrefValue(metrics::prefs::kStabilityCrashCount);
+  session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
+
+  if (!clean_exit_beacon_.exited_cleanly()) {
+    IncrementPrefValue(prefs::kStabilityCrashCount);
     // Reset flag, and wait until we call LogNeedForCleanShutdown() before
     // monitoring.
-    local_state_->SetBoolean(metrics::prefs::kStabilityExitedCleanly, true);
+    clean_exit_beacon_.WriteBeaconValue(true);
+  }
 
+  if (!clean_exit_beacon_.exited_cleanly() || ProvidersHaveStabilityMetrics()) {
     // TODO(rtenneti): On windows, consider saving/getting execution_phase from
     // the registry.
     int execution_phase =
-        local_state_->GetInteger(metrics::prefs::kStabilityExecutionPhase);
+        local_state_->GetInteger(prefs::kStabilityExecutionPhase);
     UMA_HISTOGRAM_SPARSE_SLOWLY("Chrome.Browser.CrashedExecutionPhase",
                                 execution_phase);
 
-    // If the previous session didn't exit cleanly, then prepare an initial
-    // stability log if UMA is enabled.
+    // If the previous session didn't exit cleanly, or if any provider
+    // explicitly requests it, prepare an initial stability log -
+    // provided UMA is enabled.
     if (state_manager_->IsMetricsReportingEnabled())
       PrepareInitialStabilityLog();
   }
 
+  // If no initial stability log was generated and there was a version upgrade,
+  // clear the stability stats from the previous version (so that they don't get
+  // attributed to the current version). This could otherwise happen due to a
+  // number of different edge cases, such as if the last version crashed before
+  // it could save off a system profile or if UMA reporting is disabled (which
+  // normally results in stats being accumulated).
+  if (!has_initial_stability_log_ && version_changed)
+    ClearSavedStabilityMetrics();
+
   // Update session ID.
   ++session_id_;
-  local_state_->SetInteger(metrics::prefs::kMetricsSessionID, session_id_);
+  local_state_->SetInteger(prefs::kMetricsSessionID, session_id_);
 
   // Stability bookkeeping
-  IncrementPrefValue(metrics::prefs::kStabilityLaunchCount);
+  IncrementPrefValue(prefs::kStabilityLaunchCount);
 
   DCHECK_EQ(UNINITIALIZED_PHASE, execution_phase_);
   SetExecutionPhase(START_METRICS_RECORDING, local_state_);
 
-  if (!local_state_->GetBoolean(
-          metrics::prefs::kStabilitySessionEndCompleted)) {
-    IncrementPrefValue(metrics::prefs::kStabilityIncompleteSessionEndCount);
+  if (!local_state_->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
+    IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
     // This is marked false when we get a WM_ENDSESSION.
-    local_state_->SetBoolean(metrics::prefs::kStabilitySessionEndCompleted,
-                             true);
+    local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
   }
 
   // Call GetUptimes() for the first time, thus allowing all later calls
@@ -597,13 +639,13 @@ void MetricsService::InitializeMetricsState() {
   GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter);
   DCHECK_EQ(0, startup_uptime.InMicroseconds());
   // For backwards compatibility, leave this intact in case Omaha is checking
-  // them.  metrics::prefs::kStabilityLastTimestampSec may also be useless now.
+  // them.  prefs::kStabilityLastTimestampSec may also be useless now.
   // TODO(jar): Delete these if they have no uses.
-  local_state_->SetInt64(metrics::prefs::kStabilityLaunchTimeSec,
-                         Time::Now().ToTimeT());
+  local_state_->SetInt64(prefs::kStabilityLaunchTimeSec,
+                         base::Time::Now().ToTimeT());
 
   // Bookkeeping for the uninstall metrics.
-  IncrementLongPrefsValue(metrics::prefs::kUninstallLaunchCount);
+  IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
 
   // Kick off the process of saving the state (so the uptime numbers keep
   // getting updated) every n minutes.
@@ -647,27 +689,14 @@ void MetricsService::GetUptimes(PrefService* pref,
 
   const int64 incremental_time_secs = incremental_uptime->InSeconds();
   if (incremental_time_secs > 0) {
-    int64 metrics_uptime =
-        pref->GetInt64(metrics::prefs::kUninstallMetricsUptimeSec);
+    int64 metrics_uptime = pref->GetInt64(prefs::kUninstallMetricsUptimeSec);
     metrics_uptime += incremental_time_secs;
-    pref->SetInt64(metrics::prefs::kUninstallMetricsUptimeSec, metrics_uptime);
+    pref->SetInt64(prefs::kUninstallMetricsUptimeSec, metrics_uptime);
   }
 }
 
-void MetricsService::AddObserver(MetricsServiceObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  observers_.AddObserver(observer);
-}
-
-void MetricsService::RemoveObserver(MetricsServiceObserver* observer) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  observers_.RemoveObserver(observer);
-}
-
 void MetricsService::NotifyOnDidCreateMetricsLog() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  FOR_EACH_OBSERVER(
-      MetricsServiceObserver, observers_, OnDidCreateMetricsLog());
+  DCHECK(IsSingleThreaded());
   for (size_t i = 0; i < metrics_providers_.size(); ++i)
     metrics_providers_[i]->OnDidCreateMetricsLog();
 }
@@ -735,20 +764,17 @@ void MetricsService::CloseCurrentLog() {
   // end of all log transmissions (initial log handles this separately).
   // RecordIncrementalStabilityElements only exists on the derived
   // MetricsLog class.
-  MetricsLog* current_log =
-      static_cast<MetricsLog*>(log_manager_.current_log());
+  MetricsLog* current_log = log_manager_.current_log();
   DCHECK(current_log);
-  std::vector<variations::ActiveGroupId> synthetic_trials;
-  GetCurrentSyntheticFieldTrials(&synthetic_trials);
-  current_log->RecordEnvironment(metrics_providers_.get(), synthetic_trials);
+  RecordCurrentEnvironment(current_log);
   base::TimeDelta incremental_uptime;
   base::TimeDelta uptime;
   GetUptimes(local_state_, &incremental_uptime, &uptime);
   current_log->RecordStabilityMetrics(metrics_providers_.get(),
                                       incremental_uptime, uptime);
 
-  RecordCurrentHistograms();
   current_log->RecordGeneralMetrics(metrics_providers_.get());
+  RecordCurrentHistograms();
 
   log_manager_.FinishCurrentLog();
 }
@@ -757,16 +783,6 @@ void MetricsService::PushPendingLogsToPersistentStorage() {
   if (state_ < SENDING_INITIAL_STABILITY_LOG)
     return;  // We didn't and still don't have time to get plugin list etc.
 
-  if (log_manager_.has_staged_log()) {
-    // We may race here, and send second copy of the log later.
-    metrics::PersistedLogs::StoreType store_type;
-    if (log_upload_in_progress_)
-      store_type = metrics::PersistedLogs::PROVISIONAL_STORE;
-    else
-      store_type = metrics::PersistedLogs::NORMAL_STORE;
-    log_manager_.StoreStagedLogAsUnsent(store_type);
-  }
-  DCHECK(!log_manager_.has_staged_log());
   CloseCurrentLog();
   log_manager_.PersistUnsentLogs();
 
@@ -877,18 +893,30 @@ void MetricsService::StageNewLog() {
       return;
 
     case INIT_TASK_DONE:
-      if (has_initial_stability_log_) {
-        // There's an initial stability log, ready to send.
+      if (NewInitialMetricsTimingEnabled()) {
+        PrepareInitialMetricsLog();
+        // Stage the first log, which could be a stability log (either one
+        // for created in this session or from a previous session) or the
+        // initial metrics log that was just created.
         log_manager_.StageNextLogForUpload();
-        has_initial_stability_log_ = false;
-        // Note: No need to call LoadPersistedUnsentLogs() here because unsent
-        // logs have already been loaded by PrepareInitialStabilityLog().
-        state_ = SENDING_INITIAL_STABILITY_LOG;
+        if (has_initial_stability_log_) {
+          // The initial stability log was just staged.
+          has_initial_stability_log_ = false;
+          state_ = SENDING_INITIAL_STABILITY_LOG;
+        } else {
+          state_ = SENDING_INITIAL_METRICS_LOG;
+        }
       } else {
-        PrepareInitialMetricsLog();
-        // Load unsent logs (if any) from local state.
-        log_manager_.LoadPersistedUnsentLogs();
-        state_ = SENDING_INITIAL_METRICS_LOG;
+        if (has_initial_stability_log_) {
+          // There's an initial stability log, ready to send.
+          log_manager_.StageNextLogForUpload();
+          has_initial_stability_log_ = false;
+          state_ = SENDING_INITIAL_STABILITY_LOG;
+        } else {
+          PrepareInitialMetricsLog();
+          log_manager_.StageNextLogForUpload();
+          state_ = SENDING_INITIAL_METRICS_LOG;
+        }
       }
       break;
 
@@ -910,9 +938,18 @@ void MetricsService::StageNewLog() {
   DCHECK(log_manager_.has_staged_log());
 }
 
+bool MetricsService::ProvidersHaveStabilityMetrics() {
+  // Check whether any metrics provider has stability metrics.
+  for (size_t i = 0; i < metrics_providers_.size(); ++i) {
+    if (metrics_providers_[i]->HasStabilityMetrics())
+      return true;
+  }
+
+  return false;
+}
+
 void MetricsService::PrepareInitialStabilityLog() {
   DCHECK_EQ(INITIALIZED, state_);
-  DCHECK_NE(0, local_state_->GetInteger(metrics::prefs::kStabilityCrashCount));
 
   scoped_ptr<MetricsLog> initial_stability_log(
       CreateLog(MetricsLog::INITIAL_STABILITY_LOG));
@@ -923,8 +960,6 @@ void MetricsService::PrepareInitialStabilityLog() {
   if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
     return;
 
-  log_manager_.LoadPersistedUnsentLogs();
-
   log_manager_.PauseCurrentLog();
   log_manager_.BeginLoggingWithLog(initial_stability_log.Pass());
 
@@ -950,10 +985,7 @@ void MetricsService::PrepareInitialStabilityLog() {
 void MetricsService::PrepareInitialMetricsLog() {
   DCHECK(state_ == INIT_TASK_DONE || state_ == SENDING_INITIAL_STABILITY_LOG);
 
-  std::vector<variations::ActiveGroupId> synthetic_trials;
-  GetCurrentSyntheticFieldTrials(&synthetic_trials);
-  initial_metrics_log_->RecordEnvironment(metrics_providers_.get(),
-                                          synthetic_trials);
+  RecordCurrentEnvironment(initial_metrics_log_.get());
   base::TimeDelta incremental_uptime;
   base::TimeDelta uptime;
   GetUptimes(local_state_, &incremental_uptime, &uptime);
@@ -965,19 +997,18 @@ void MetricsService::PrepareInitialMetricsLog() {
 
   // Note: Some stability providers may record stability stats via histograms,
   //       so this call has to be after BeginLoggingWithLog().
-  MetricsLog* current_log =
-      static_cast<MetricsLog*>(log_manager_.current_log());
+  MetricsLog* current_log = log_manager_.current_log();
   current_log->RecordStabilityMetrics(metrics_providers_.get(),
                                       base::TimeDelta(), base::TimeDelta());
-  RecordCurrentHistograms();
-
   current_log->RecordGeneralMetrics(metrics_providers_.get());
+  RecordCurrentHistograms();
 
   log_manager_.FinishCurrentLog();
   log_manager_.ResumePausedLog();
 
-  DCHECK(!log_manager_.has_staged_log());
-  log_manager_.StageNextLogForUpload();
+  // Store unsent logs, including the initial log that was just saved, so
+  // that they're not lost in case of a crash before upload time.
+  log_manager_.PersistUnsentLogs();
 }
 
 void MetricsService::SendStagedLog() {
@@ -1021,16 +1052,14 @@ void MetricsService::OnLogUploadComplete(int response_code) {
                             ResponseCodeToStatus(response_code),
                             NUM_RESPONSE_STATUSES);
 
-  // If the upload was provisionally stored, drop it now that the upload is
-  // known to have gone through.
-  log_manager_.DiscardLastProvisionalStore();
-
   bool upload_succeeded = response_code == 200;
 
   // Provide boolean for error recovery (allow us to ignore response_code).
   bool discard_log = false;
   const size_t log_size = log_manager_.staged_log().length();
-  if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) {
+  if (upload_succeeded) {
+    UMA_HISTOGRAM_COUNTS_10000("UMA.LogSize.OnSuccess", log_size / 1024);
+  } else if (log_size > kUploadLogAvoidRetransmitSize) {
     UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
                          static_cast<int>(log_size));
     discard_log = true;
@@ -1039,31 +1068,32 @@ void MetricsService::OnLogUploadComplete(int response_code) {
     discard_log = true;
   }
 
-  if (upload_succeeded || discard_log)
+  if (upload_succeeded || discard_log) {
     log_manager_.DiscardStagedLog();
+    // Store the updated list to disk now that the removed log is uploaded.
+    log_manager_.PersistUnsentLogs();
+  }
 
   if (!log_manager_.has_staged_log()) {
     switch (state_) {
       case SENDING_INITIAL_STABILITY_LOG:
-        // Store the updated list to disk now that the removed log is uploaded.
-        log_manager_.PersistUnsentLogs();
-        PrepareInitialMetricsLog();
-        SendStagedLog();
-        state_ = SENDING_INITIAL_METRICS_LOG;
+        if (NewInitialMetricsTimingEnabled()) {
+          // The initial metrics log is already in the queue of unsent logs.
+          state_ = SENDING_OLD_LOGS;
+        } else {
+          PrepareInitialMetricsLog();
+          log_manager_.StageNextLogForUpload();
+          SendStagedLog();
+          state_ = SENDING_INITIAL_METRICS_LOG;
+        }
         break;
 
       case SENDING_INITIAL_METRICS_LOG:
-        // The initial metrics log never gets persisted to local state, so it's
-        // not necessary to call log_manager_.PersistUnsentLogs() here.
-        // TODO(asvitkine): It should be persisted like the initial stability
-        // log and old unsent logs. http://crbug.com/328417
         state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS
                                                 : SENDING_CURRENT_LOGS;
         break;
 
       case SENDING_OLD_LOGS:
-        // Store the updated list to disk now that the removed log is uploaded.
-        log_manager_.PersistUnsentLogs();
         if (!log_manager_.has_unsent_logs())
           state_ = SENDING_CURRENT_LOGS;
         break;
@@ -1111,6 +1141,18 @@ bool MetricsService::UmaMetricsProperlyShutdown() {
   return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
 }
 
+void MetricsService::AddSyntheticTrialObserver(
+    SyntheticTrialObserver* observer) {
+  synthetic_trial_observer_list_.AddObserver(observer);
+  if (!synthetic_trial_groups_.empty())
+    observer->OnSyntheticTrialsChanged(synthetic_trial_groups_);
+}
+
+void MetricsService::RemoveSyntheticTrialObserver(
+    SyntheticTrialObserver* observer) {
+  synthetic_trial_observer_list_.RemoveObserver(observer);
+}
+
 void MetricsService::RegisterSyntheticFieldTrial(
     const SyntheticTrialGroup& trial) {
   for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
@@ -1118,6 +1160,7 @@ void MetricsService::RegisterSyntheticFieldTrial(
       if (synthetic_trial_groups_[i].id.group != trial.id.group) {
         synthetic_trial_groups_[i].id.group = trial.id.group;
         synthetic_trial_groups_[i].start_time = base::TimeTicks::Now();
+        NotifySyntheticTrialObservers();
       }
       return;
     }
@@ -1126,10 +1169,11 @@ void MetricsService::RegisterSyntheticFieldTrial(
   SyntheticTrialGroup trial_group = trial;
   trial_group.start_time = base::TimeTicks::Now();
   synthetic_trial_groups_.push_back(trial_group);
+  NotifySyntheticTrialObservers();
 }
 
 void MetricsService::RegisterMetricsProvider(
-    scoped_ptr<metrics::MetricsProvider> provider) {
+    scoped_ptr<MetricsProvider> provider) {
   DCHECK_EQ(INITIALIZED, state_);
   metrics_providers_.push_back(provider.release());
 }
@@ -1139,12 +1183,16 @@ void MetricsService::CheckForClonedInstall(
   state_manager_->CheckForClonedInstall(task_runner);
 }
 
+void MetricsService::NotifySyntheticTrialObservers() {
+  FOR_EACH_OBSERVER(SyntheticTrialObserver, synthetic_trial_observer_list_,
+                    OnSyntheticTrialsChanged(synthetic_trial_groups_));
+}
+
 void MetricsService::GetCurrentSyntheticFieldTrials(
     std::vector<variations::ActiveGroupId>* synthetic_trials) {
   DCHECK(synthetic_trials);
   synthetic_trials->clear();
-  const MetricsLog* current_log =
-      static_cast<const MetricsLog*>(log_manager_.current_log());
+  const MetricsLog* current_log = log_manager_.current_log();
   for (size_t i = 0; i < synthetic_trial_groups_.size(); ++i) {
     if (synthetic_trial_groups_[i].start_time <= current_log->creation_time())
       synthetic_trials->push_back(synthetic_trial_groups_[i].id);
@@ -1159,6 +1207,15 @@ scoped_ptr<MetricsLog> MetricsService::CreateLog(MetricsLog::LogType log_type) {
                                         local_state_));
 }
 
+void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
+  std::vector<variations::ActiveGroupId> synthetic_trials;
+  GetCurrentSyntheticFieldTrials(&synthetic_trials);
+  log->RecordEnvironment(metrics_providers_.get(), synthetic_trials,
+                         GetInstallDate());
+  UMA_HISTOGRAM_COUNTS_100("UMA.SyntheticTrials.Count",
+                           synthetic_trials.size());
+}
+
 void MetricsService::RecordCurrentHistograms() {
   DCHECK(log_manager_.current_log());
   histogram_snapshot_manager_.PrepareDeltas(
@@ -1173,14 +1230,15 @@ void MetricsService::RecordCurrentStabilityHistograms() {
 
 void MetricsService::LogCleanShutdown() {
   // Redundant hack to write pref ASAP.
-  MarkAppCleanShutdownAndCommit(local_state_);
+  MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
 
   // Redundant setting to assure that we always reset this value at shutdown
   // (and that we don't use some alternate path, and not call LogCleanShutdown).
   clean_shutdown_status_ = CLEANLY_SHUTDOWN;
 
-  RecordBooleanPrefValue(metrics::prefs::kStabilityExitedCleanly, true);
-  local_state_->SetInteger(metrics::prefs::kStabilityExecutionPhase,
+  clean_exit_beacon_.WriteBeaconValue(true);
+  RecordCurrentState(local_state_);
+  local_state_->SetInteger(prefs::kStabilityExecutionPhase,
                            MetricsService::SHUTDOWN_COMPLETE);
 }
 
@@ -1198,9 +1256,8 @@ void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
 }
 
 void MetricsService::RecordCurrentState(PrefService* pref) {
-  pref->SetInt64(metrics::prefs::kStabilityLastTimestampSec,
-                 Time::Now().ToTimeT());
-
-  for (size_t i = 0; i < metrics_providers_.size(); ++i)
-    metrics_providers_[i]->RecordCurrentState();
+  pref->SetInt64(prefs::kStabilityLastTimestampSec,
+                 base::Time::Now().ToTimeT());
 }
+
+}  // namespace metrics