| Index: trunk/src/chrome/browser/metrics/metrics_service.cc
|
| ===================================================================
|
| --- trunk/src/chrome/browser/metrics/metrics_service.cc (revision 268245)
|
| +++ trunk/src/chrome/browser/metrics/metrics_service.cc (working copy)
|
| @@ -168,12 +168,14 @@
|
| #include "base/bind.h"
|
| #include "base/callback.h"
|
| #include "base/command_line.h"
|
| +#include "base/guid.h"
|
| #include "base/metrics/histogram.h"
|
| #include "base/metrics/sparse_histogram.h"
|
| #include "base/metrics/statistics_recorder.h"
|
| #include "base/prefs/pref_registry_simple.h"
|
| #include "base/prefs/pref_service.h"
|
| #include "base/prefs/scoped_user_pref_update.h"
|
| +#include "base/rand_util.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/threading/platform_thread.h"
|
| @@ -185,11 +187,12 @@
|
| #include "chrome/browser/chrome_notification_types.h"
|
| #include "chrome/browser/io_thread.h"
|
| #include "chrome/browser/memory_details.h"
|
| +#include "chrome/browser/metrics/cloned_install_detector.h"
|
| #include "chrome/browser/metrics/compression_utils.h"
|
| +#include "chrome/browser/metrics/machine_id_provider.h"
|
| #include "chrome/browser/metrics/metrics_log.h"
|
| #include "chrome/browser/metrics/metrics_log_serializer.h"
|
| #include "chrome/browser/metrics/metrics_reporting_scheduler.h"
|
| -#include "chrome/browser/metrics/metrics_state_manager.h"
|
| #include "chrome/browser/metrics/time_ticks_experiment_win.h"
|
| #include "chrome/browser/metrics/tracking_synchronizer.h"
|
| #include "chrome/common/metrics/variations/variations_util.h"
|
| @@ -203,6 +206,7 @@
|
| #include "chrome/common/chrome_result_codes.h"
|
| #include "chrome/common/chrome_switches.h"
|
| #include "chrome/common/crash_keys.h"
|
| +#include "chrome/common/metrics/caching_permuted_entropy_provider.h"
|
| #include "chrome/common/net/test_server_locations.h"
|
| #include "chrome/common/pref_names.h"
|
| #include "chrome/common/render_messages.h"
|
| @@ -309,6 +313,21 @@
|
| }
|
| }
|
|
|
| +// The argument used to generate a non-identifying entropy source. We want no
|
| +// more than 13 bits of entropy, so use this max to return a number in the range
|
| +// [0, 7999] as the entropy source (12.97 bits of entropy).
|
| +const int kMaxLowEntropySize = 8000;
|
| +
|
| +// Default prefs value for prefs::kMetricsLowEntropySource to indicate that the
|
| +// value has not yet been set.
|
| +const int kLowEntropySourceNotSet = -1;
|
| +
|
| +// Generates a new non-identifying entropy source used to seed persistent
|
| +// activities.
|
| +int GenerateLowEntropySource() {
|
| + return base::RandInt(0, kMaxLowEntropySize - 1);
|
| +}
|
| +
|
| // Converts an exit code into something that can be inserted into our
|
| // histograms (which expect non-negative numbers less than MAX_INT).
|
| int MapCrashExitCodeForHistogram(int exit_code) {
|
| @@ -411,8 +430,11 @@
|
| // static
|
| void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
|
| DCHECK(IsSingleThreaded());
|
| - metrics::MetricsStateManager::RegisterPrefs(registry);
|
| -
|
| + registry->RegisterBooleanPref(prefs::kMetricsResetIds, false);
|
| + registry->RegisterStringPref(prefs::kMetricsClientID, std::string());
|
| + registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
|
| + registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
|
| + kLowEntropySourceNotSet);
|
| registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
|
| registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
|
| registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
|
| @@ -457,28 +479,33 @@
|
| registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
|
| registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
|
|
|
| + // TODO(asvitkine): Remove these once a couple of releases have passed.
|
| + // http://crbug.com/357704
|
| + registry->RegisterStringPref(prefs::kMetricsOldClientID, std::string());
|
| + registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource, 0);
|
| +
|
| #if defined(OS_ANDROID)
|
| RegisterPrefsAndroid(registry);
|
| #endif // defined(OS_ANDROID)
|
| }
|
|
|
| MetricsService::MetricsService()
|
| - : state_manager_(metrics::MetricsStateManager::Create(
|
| - g_browser_process->local_state())),
|
| + : metrics_ids_reset_check_performed_(false),
|
| recording_active_(false),
|
| reporting_active_(false),
|
| test_mode_active_(false),
|
| state_(INITIALIZED),
|
| has_initial_stability_log_(false),
|
| + low_entropy_source_(kLowEntropySourceNotSet),
|
| idle_since_last_transmission_(false),
|
| session_id_(-1),
|
| next_window_id_(0),
|
| self_ptr_factory_(this),
|
| state_saver_factory_(this),
|
| waiting_for_asynchronous_reporting_step_(false),
|
| - num_async_histogram_fetches_in_progress_(0) {
|
| + num_async_histogram_fetches_in_progress_(0),
|
| + entropy_source_returned_(LAST_ENTROPY_NONE) {
|
| DCHECK(IsSingleThreaded());
|
| - DCHECK(state_manager_);
|
|
|
| log_manager_.set_log_serializer(new MetricsLogSerializer);
|
| log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize);
|
| @@ -492,8 +519,9 @@
|
| BrowserChildProcessObserver::Remove(this);
|
| }
|
|
|
| -void MetricsService::InitializeMetricsRecordingState() {
|
| - InitializeMetricsState();
|
| +void MetricsService::InitializeMetricsRecordingState(
|
| + ReportingState reporting_state) {
|
| + InitializeMetricsState(reporting_state);
|
|
|
| base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
|
| self_ptr_factory_.GetWeakPtr());
|
| @@ -506,13 +534,6 @@
|
| EnableReporting();
|
| }
|
|
|
| -bool MetricsService::StartIfMetricsReportingEnabled() {
|
| - const bool enabled = state_manager_->IsMetricsReportingEnabled();
|
| - if (enabled)
|
| - Start();
|
| - return enabled;
|
| -}
|
| -
|
| void MetricsService::StartRecordingForTests() {
|
| test_mode_active_ = true;
|
| EnableRecording();
|
| @@ -537,16 +558,72 @@
|
| }
|
|
|
| std::string MetricsService::GetClientId() {
|
| - return state_manager_->client_id();
|
| + return client_id_;
|
| }
|
|
|
| scoped_ptr<const base::FieldTrial::EntropyProvider>
|
| -MetricsService::CreateEntropyProvider() {
|
| - // TODO(asvitkine): Refactor the code so that MetricsService does not expose
|
| - // this method.
|
| - return state_manager_->CreateEntropyProvider();
|
| +MetricsService::CreateEntropyProvider(ReportingState reporting_state) {
|
| + // For metrics reporting-enabled users, we combine the client ID and low
|
| + // entropy source to get the final entropy source. Otherwise, only use the low
|
| + // entropy source.
|
| + // This has two useful properties:
|
| + // 1) It makes the entropy source less identifiable for parties that do not
|
| + // know the low entropy source.
|
| + // 2) It makes the final entropy source resettable.
|
| + const int low_entropy_source_value = GetLowEntropySource();
|
| + UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue",
|
| + low_entropy_source_value);
|
| + if (reporting_state == REPORTING_ENABLED) {
|
| + if (entropy_source_returned_ == LAST_ENTROPY_NONE)
|
| + entropy_source_returned_ = LAST_ENTROPY_HIGH;
|
| + DCHECK_EQ(LAST_ENTROPY_HIGH, entropy_source_returned_);
|
| + const std::string high_entropy_source =
|
| + client_id_ + base::IntToString(low_entropy_source_value);
|
| + return scoped_ptr<const base::FieldTrial::EntropyProvider>(
|
| + new metrics::SHA1EntropyProvider(high_entropy_source));
|
| + }
|
| +
|
| + if (entropy_source_returned_ == LAST_ENTROPY_NONE)
|
| + entropy_source_returned_ = LAST_ENTROPY_LOW;
|
| + DCHECK_EQ(LAST_ENTROPY_LOW, entropy_source_returned_);
|
| +
|
| +#if defined(OS_ANDROID) || defined(OS_IOS)
|
| + return scoped_ptr<const base::FieldTrial::EntropyProvider>(
|
| + new metrics::CachingPermutedEntropyProvider(
|
| + g_browser_process->local_state(),
|
| + low_entropy_source_value,
|
| + kMaxLowEntropySize));
|
| +#else
|
| + return scoped_ptr<const base::FieldTrial::EntropyProvider>(
|
| + new metrics::PermutedEntropyProvider(low_entropy_source_value,
|
| + kMaxLowEntropySize));
|
| +#endif
|
| }
|
|
|
| +void MetricsService::ForceClientIdCreation() {
|
| + if (!client_id_.empty())
|
| + return;
|
| +
|
| + ResetMetricsIDsIfNecessary();
|
| +
|
| + PrefService* pref = g_browser_process->local_state();
|
| + client_id_ = pref->GetString(prefs::kMetricsClientID);
|
| + if (!client_id_.empty())
|
| + return;
|
| +
|
| + client_id_ = GenerateClientID();
|
| + pref->SetString(prefs::kMetricsClientID, client_id_);
|
| +
|
| + if (pref->GetString(prefs::kMetricsOldClientID).empty()) {
|
| + // Record the timestamp of when the user opted in to UMA.
|
| + pref->SetInt64(prefs::kMetricsReportingEnabledTimestamp,
|
| + Time::Now().ToTimeT());
|
| + } else {
|
| + UMA_HISTOGRAM_BOOLEAN("UMA.ClientIdMigrated", true);
|
| + }
|
| + pref->ClearPref(prefs::kMetricsOldClientID);
|
| +}
|
| +
|
| void MetricsService::EnableRecording() {
|
| DCHECK(IsSingleThreaded());
|
|
|
| @@ -554,8 +631,8 @@
|
| return;
|
| recording_active_ = true;
|
|
|
| - state_manager_->ForceClientIdCreation();
|
| - crash_keys::SetClientID(state_manager_->client_id());
|
| + ForceClientIdCreation();
|
| + crash_keys::SetClientID(client_id_);
|
| if (!log_manager_.current_log())
|
| OpenNewLog();
|
|
|
| @@ -841,7 +918,7 @@
|
| //------------------------------------------------------------------------------
|
| // Initialization methods
|
|
|
| -void MetricsService::InitializeMetricsState() {
|
| +void MetricsService::InitializeMetricsState(ReportingState reporting_state) {
|
| #if defined(OS_POSIX)
|
| network_stats_server_ = chrome_common_net::kEchoTestServerLocation;
|
| http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl;
|
| @@ -878,7 +955,7 @@
|
|
|
| // If the previous session didn't exit cleanly, then prepare an initial
|
| // stability log if UMA is enabled.
|
| - if (state_manager_->IsMetricsReportingEnabled())
|
| + if (reporting_state == REPORTING_ENABLED)
|
| PrepareInitialStabilityLog();
|
| }
|
|
|
| @@ -1042,8 +1119,7 @@
|
| // save the profiler data.
|
| if (!initial_metrics_log_.get()) {
|
| initial_metrics_log_.reset(
|
| - new MetricsLog(state_manager_->client_id(), session_id_,
|
| - MetricsLog::ONGOING_LOG));
|
| + new MetricsLog(client_id_, session_id_, MetricsLog::ONGOING_LOG));
|
| }
|
|
|
| initial_metrics_log_->RecordProfilerData(process_data, process_type);
|
| @@ -1077,6 +1153,64 @@
|
| }
|
| }
|
|
|
| +void MetricsService::ResetMetricsIDsIfNecessary() {
|
| + if (metrics_ids_reset_check_performed_)
|
| + return;
|
| +
|
| + metrics_ids_reset_check_performed_ = true;
|
| +
|
| + PrefService* local_state = g_browser_process->local_state();
|
| + if (!local_state->GetBoolean(prefs::kMetricsResetIds))
|
| + return;
|
| +
|
| + UMA_HISTOGRAM_BOOLEAN("UMA.MetricsIDsReset", true);
|
| +
|
| + DCHECK(client_id_.empty());
|
| + DCHECK_EQ(kLowEntropySourceNotSet, low_entropy_source_);
|
| +
|
| + local_state->ClearPref(prefs::kMetricsClientID);
|
| + local_state->ClearPref(prefs::kMetricsLowEntropySource);
|
| + local_state->ClearPref(prefs::kMetricsResetIds);
|
| +}
|
| +
|
| +int MetricsService::GetLowEntropySource() {
|
| + // Note that the default value for the low entropy source and the default pref
|
| + // value are both kLowEntropySourceNotSet, which is used to identify if the
|
| + // value has been set or not.
|
| + if (low_entropy_source_ != kLowEntropySourceNotSet)
|
| + return low_entropy_source_;
|
| +
|
| + ResetMetricsIDsIfNecessary();
|
| +
|
| + PrefService* local_state = g_browser_process->local_state();
|
| + const CommandLine* command_line(CommandLine::ForCurrentProcess());
|
| + // Only try to load the value from prefs if the user did not request a reset.
|
| + // Otherwise, skip to generating a new value.
|
| + if (!command_line->HasSwitch(switches::kResetVariationState)) {
|
| + int value = local_state->GetInteger(prefs::kMetricsLowEntropySource);
|
| + // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
|
| + // it below.
|
| + if (value >= 0 && value < kMaxLowEntropySize) {
|
| + low_entropy_source_ = value;
|
| + UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
|
| + return low_entropy_source_;
|
| + }
|
| + }
|
| +
|
| + UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true);
|
| + low_entropy_source_ = GenerateLowEntropySource();
|
| + local_state->SetInteger(prefs::kMetricsLowEntropySource, low_entropy_source_);
|
| + local_state->ClearPref(prefs::kMetricsOldLowEntropySource);
|
| + metrics::CachingPermutedEntropyProvider::ClearCache(local_state);
|
| +
|
| + return low_entropy_source_;
|
| +}
|
| +
|
| +// static
|
| +std::string MetricsService::GenerateClientID() {
|
| + return base::GenerateGUID();
|
| +}
|
| +
|
| //------------------------------------------------------------------------------
|
| // State save methods
|
|
|
| @@ -1110,8 +1244,7 @@
|
| DCHECK(!log_manager_.current_log());
|
|
|
| log_manager_.BeginLoggingWithLog(
|
| - new MetricsLog(state_manager_->client_id(), session_id_,
|
| - MetricsLog::ONGOING_LOG));
|
| + new MetricsLog(client_id_, session_id_, MetricsLog::ONGOING_LOG));
|
| if (state_ == INITIALIZED) {
|
| // We only need to schedule that run once.
|
| state_ = INIT_TASK_SCHEDULED;
|
| @@ -1407,7 +1540,7 @@
|
| DCHECK_NE(0, pref->GetInteger(prefs::kStabilityCrashCount));
|
|
|
| scoped_ptr<MetricsLog> initial_stability_log(
|
| - new MetricsLog(state_manager_->client_id(), session_id_,
|
| + new MetricsLog(client_id_, session_id_,
|
| MetricsLog::INITIAL_STABILITY_LOG));
|
| if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
|
| return;
|
| @@ -1706,7 +1839,18 @@
|
| }
|
|
|
| void MetricsService::CheckForClonedInstall() {
|
| - state_manager_->CheckForClonedInstall();
|
| + DCHECK(!cloned_install_detector_);
|
| +
|
| + metrics::MachineIdProvider* provider =
|
| + metrics::MachineIdProvider::CreateInstance();
|
| + if (!provider)
|
| + return;
|
| +
|
| + cloned_install_detector_.reset(
|
| + new metrics::ClonedInstallDetector(provider));
|
| +
|
| + PrefService* local_state = g_browser_process->local_state();
|
| + cloned_install_detector_->CheckForClonedInstall(local_state);
|
| }
|
|
|
| void MetricsService::GetCurrentSyntheticFieldTrials(
|
|
|