123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/metrics/metrics_service.h"
- #include <stdint.h>
- #include <algorithm>
- #include <memory>
- #include <string>
- #include "base/bind.h"
- #include "base/containers/contains.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/memory/raw_ptr.h"
- #include "base/metrics/field_trial.h"
- #include "base/metrics/histogram_functions.h"
- #include "base/metrics/metrics_hashes.h"
- #include "base/metrics/statistics_recorder.h"
- #include "base/metrics/user_metrics.h"
- #include "base/test/bind.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/test_simple_task_runner.h"
- #include "base/threading/platform_thread.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "build/build_config.h"
- #include "components/metrics/clean_exit_beacon.h"
- #include "components/metrics/client_info.h"
- #include "components/metrics/environment_recorder.h"
- #include "components/metrics/log_decoder.h"
- #include "components/metrics/metrics_log.h"
- #include "components/metrics/metrics_pref_names.h"
- #include "components/metrics/metrics_state_manager.h"
- #include "components/metrics/metrics_upload_scheduler.h"
- #include "components/metrics/stability_metrics_helper.h"
- #include "components/metrics/test/test_enabled_state_provider.h"
- #include "components/metrics/test/test_metrics_provider.h"
- #include "components/metrics/test/test_metrics_service_client.h"
- #include "components/metrics/unsent_log_store_metrics_impl.h"
- #include "components/prefs/testing_pref_service.h"
- #include "components/variations/active_field_trials.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
- #include "third_party/metrics_proto/system_profile.pb.h"
- #include "third_party/zlib/google/compression_utils.h"
- namespace metrics {
- namespace {
- const char kTestPrefName[] = "TestPref";
- class TestUnsentLogStore : public UnsentLogStore {
- public:
- explicit TestUnsentLogStore(PrefService* service)
- : UnsentLogStore(std::make_unique<UnsentLogStoreMetricsImpl>(),
- service,
- kTestPrefName,
- nullptr,
- /* min_log_count= */ 3,
- /* min_log_bytes= */ 1,
- /* max_log_size= */ 0,
- std::string()) {}
- ~TestUnsentLogStore() override = default;
- TestUnsentLogStore(const TestUnsentLogStore&) = delete;
- TestUnsentLogStore& operator=(const TestUnsentLogStore&) = delete;
- static void RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterListPref(kTestPrefName);
- }
- };
- void YieldUntil(base::Time when) {
- while (base::Time::Now() <= when)
- base::PlatformThread::YieldCurrentThread();
- }
- // Returns true if |id| is present in |proto|'s collection of FieldTrials.
- bool IsFieldTrialPresent(const SystemProfileProto& proto,
- const std::string& trial_name,
- const std::string& group_name) {
- const variations::ActiveGroupId id =
- variations::MakeActiveGroupId(trial_name, group_name);
- for (const auto& trial : proto.field_trial()) {
- if (trial.name_id() == id.name && trial.group_id() == id.group)
- return true;
- }
- return false;
- }
- class TestMetricsService : public MetricsService {
- public:
- TestMetricsService(MetricsStateManager* state_manager,
- MetricsServiceClient* client,
- PrefService* local_state)
- : MetricsService(state_manager, client, local_state) {}
- TestMetricsService(const TestMetricsService&) = delete;
- TestMetricsService& operator=(const TestMetricsService&) = delete;
- ~TestMetricsService() override = default;
- using MetricsService::INIT_TASK_SCHEDULED;
- using MetricsService::RecordCurrentEnvironmentHelper;
- using MetricsService::SENDING_LOGS;
- using MetricsService::state;
- // MetricsService:
- void SetPersistentSystemProfile(const std::string& serialized_proto,
- bool complete) override {
- persistent_system_profile_provided_ = true;
- persistent_system_profile_complete_ = complete;
- }
- bool persistent_system_profile_provided() const {
- return persistent_system_profile_provided_;
- }
- bool persistent_system_profile_complete() const {
- return persistent_system_profile_complete_;
- }
- private:
- bool persistent_system_profile_provided_ = false;
- bool persistent_system_profile_complete_ = false;
- };
- class TestMetricsLog : public MetricsLog {
- public:
- TestMetricsLog(const std::string& client_id,
- int session_id,
- MetricsServiceClient* client)
- : MetricsLog(client_id, session_id, MetricsLog::ONGOING_LOG, client) {}
- TestMetricsLog(const TestMetricsLog&) = delete;
- TestMetricsLog& operator=(const TestMetricsLog&) = delete;
- ~TestMetricsLog() override {}
- };
- const char kOnDidCreateMetricsLogHistogramName[] = "Test.OnDidCreateMetricsLog";
- class TestMetricsProviderForOnDidCreateMetricsLog : public TestMetricsProvider {
- public:
- TestMetricsProviderForOnDidCreateMetricsLog() = default;
- ~TestMetricsProviderForOnDidCreateMetricsLog() override = default;
- void OnDidCreateMetricsLog() override {
- base::UmaHistogramBoolean(kOnDidCreateMetricsLogHistogramName, true);
- }
- };
- class MetricsServiceTest : public testing::Test {
- public:
- MetricsServiceTest()
- : task_runner_(new base::TestSimpleTaskRunner),
- task_runner_handle_(task_runner_),
- enabled_state_provider_(new TestEnabledStateProvider(false, false)) {
- base::SetRecordActionTaskRunner(task_runner_);
- MetricsService::RegisterPrefs(testing_local_state_.registry());
- }
- MetricsServiceTest(const MetricsServiceTest&) = delete;
- MetricsServiceTest& operator=(const MetricsServiceTest&) = delete;
- ~MetricsServiceTest() override {}
- void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
- MetricsStateManager* GetMetricsStateManager(
- const base::FilePath& user_data_dir = base::FilePath(),
- StartupVisibility startup_visibility = StartupVisibility::kUnknown) {
- // Lazy-initialize the metrics_state_manager so that it correctly reads the
- // stability state from prefs after tests have a chance to initialize it.
- if (!metrics_state_manager_) {
- metrics_state_manager_ = MetricsStateManager::Create(
- GetLocalState(), enabled_state_provider_.get(), std::wstring(),
- user_data_dir, startup_visibility);
- metrics_state_manager_->InstantiateFieldTrialList();
- }
- return metrics_state_manager_.get();
- }
- std::unique_ptr<TestUnsentLogStore> InitializeTestLogStoreAndGet() {
- TestUnsentLogStore::RegisterPrefs(testing_local_state_.registry());
- return std::make_unique<TestUnsentLogStore>(GetLocalState());
- }
- PrefService* GetLocalState() { return &testing_local_state_; }
- // Sets metrics reporting as enabled for testing.
- void EnableMetricsReporting() { SetMetricsReporting(true); }
- // Sets metrics reporting for testing.
- void SetMetricsReporting(bool enabled) {
- enabled_state_provider_->set_consent(enabled);
- enabled_state_provider_->set_enabled(enabled);
- }
- // Finds a histogram with the specified |name_hash| in |histograms|.
- const base::HistogramBase* FindHistogram(
- const base::StatisticsRecorder::Histograms& histograms,
- uint64_t name_hash) {
- for (const base::HistogramBase* histogram : histograms) {
- if (name_hash == base::HashMetricName(histogram->histogram_name()))
- return histogram;
- }
- return nullptr;
- }
- // Checks whether |uma_log| contains any histograms that are not flagged
- // with kUmaStabilityHistogramFlag. Stability logs should only contain such
- // histograms.
- void CheckForNonStabilityHistograms(
- const ChromeUserMetricsExtension& uma_log) {
- const int kStabilityFlags = base::HistogramBase::kUmaStabilityHistogramFlag;
- const base::StatisticsRecorder::Histograms histograms =
- base::StatisticsRecorder::GetHistograms();
- for (int i = 0; i < uma_log.histogram_event_size(); ++i) {
- const uint64_t hash = uma_log.histogram_event(i).name_hash();
- const base::HistogramBase* histogram = FindHistogram(histograms, hash);
- EXPECT_TRUE(histogram) << hash;
- EXPECT_EQ(kStabilityFlags, histogram->flags() & kStabilityFlags) << hash;
- }
- }
- // Returns the number of samples logged to the specified histogram or 0 if
- // the histogram was not found.
- int GetHistogramSampleCount(const ChromeUserMetricsExtension& uma_log,
- base::StringPiece histogram_name) {
- const auto histogram_name_hash = base::HashMetricName(histogram_name);
- int samples = 0;
- for (int i = 0; i < uma_log.histogram_event_size(); ++i) {
- const auto& histogram = uma_log.histogram_event(i);
- if (histogram.name_hash() == histogram_name_hash) {
- for (int j = 0; j < histogram.bucket_size(); ++j) {
- const auto& bucket = histogram.bucket(j);
- // Per proto comments, count field not being set means 1 sample.
- samples += (!bucket.has_count() ? 1 : bucket.count());
- }
- }
- }
- return samples;
- }
- // Returns the sampled count of the |kOnDidCreateMetricsLogHistogramName|
- // histogram in the currently staged log in |test_log_store|.
- int GetSampleCountOfOnDidCreateLogHistogram(MetricsLogStore* test_log_store) {
- ChromeUserMetricsExtension log;
- EXPECT_TRUE(DecodeLogDataToProto(test_log_store->staged_log(), &log));
- return GetHistogramSampleCount(log, kOnDidCreateMetricsLogHistogramName);
- }
- int GetNumberOfUserActions(MetricsLogStore* test_log_store) {
- ChromeUserMetricsExtension log;
- EXPECT_TRUE(DecodeLogDataToProto(test_log_store->staged_log(), &log));
- return log.user_action_event_size();
- }
- const base::FilePath user_data_dir_path() { return temp_dir_.GetPath(); }
- protected:
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
- base::test::ScopedFeatureList feature_list_;
- private:
- std::unique_ptr<TestEnabledStateProvider> enabled_state_provider_;
- TestingPrefServiceSimple testing_local_state_;
- std::unique_ptr<MetricsStateManager> metrics_state_manager_;
- base::ScopedTempDir temp_dir_;
- };
- class MetricsServiceTestWithConsolidateInitialLogLogicFeature
- : public MetricsServiceTest,
- public ::testing::WithParamInterface<bool> {
- public:
- MetricsServiceTestWithConsolidateInitialLogLogicFeature() = default;
- ~MetricsServiceTestWithConsolidateInitialLogLogicFeature() override = default;
- bool ShouldConsolidateInitialLogLogic() { return GetParam(); }
- void SetUp() override {
- MetricsServiceTest::SetUp();
- if (ShouldConsolidateInitialLogLogic()) {
- feature_list_.InitWithFeatures(
- {kConsolidateMetricsServiceInitialLogLogic}, {});
- } else {
- feature_list_.InitWithFeatures(
- {}, {kConsolidateMetricsServiceInitialLogLogic});
- }
- }
- private:
- base::test::ScopedFeatureList feature_list_;
- };
- struct StartupVisibilityTestParams {
- const std::string test_name;
- metrics::StartupVisibility startup_visibility;
- bool consolidate_initial_log_logic;
- bool expected_beacon_value;
- };
- class MetricsServiceTestWithStartupVisibility
- : public MetricsServiceTest,
- public ::testing::WithParamInterface<StartupVisibilityTestParams> {
- public:
- MetricsServiceTestWithStartupVisibility() = default;
- ~MetricsServiceTestWithStartupVisibility() override = default;
- bool ShouldConsolidateInitialLogLogic() {
- return GetParam().consolidate_initial_log_logic;
- }
- void SetUp() override {
- MetricsServiceTest::SetUp();
- if (ShouldConsolidateInitialLogLogic()) {
- feature_list_.InitWithFeatures(
- {kConsolidateMetricsServiceInitialLogLogic}, {});
- } else {
- feature_list_.InitWithFeatures(
- {}, {kConsolidateMetricsServiceInitialLogLogic});
- }
- }
- private:
- base::test::ScopedFeatureList feature_list_;
- };
- class ExperimentTestMetricsProvider : public TestMetricsProvider {
- public:
- explicit ExperimentTestMetricsProvider(
- base::FieldTrial* profile_metrics_trial,
- base::FieldTrial* session_data_trial)
- : profile_metrics_trial_(profile_metrics_trial),
- session_data_trial_(session_data_trial) {}
- ~ExperimentTestMetricsProvider() override = default;
- void ProvideSystemProfileMetrics(
- SystemProfileProto* system_profile_proto) override {
- TestMetricsProvider::ProvideSystemProfileMetrics(system_profile_proto);
- profile_metrics_trial_->group();
- }
- void ProvideCurrentSessionData(
- ChromeUserMetricsExtension* uma_proto) override {
- TestMetricsProvider::ProvideCurrentSessionData(uma_proto);
- session_data_trial_->group();
- }
- private:
- raw_ptr<base::FieldTrial> profile_metrics_trial_;
- raw_ptr<base::FieldTrial> session_data_trial_;
- };
- bool HistogramExists(base::StringPiece name) {
- return base::StatisticsRecorder::FindHistogram(name) != nullptr;
- }
- base::HistogramBase::Count GetHistogramDeltaTotalCount(base::StringPiece name) {
- return base::StatisticsRecorder::FindHistogram(name)
- ->SnapshotDelta()
- ->TotalCount();
- }
- } // namespace
- INSTANTIATE_TEST_SUITE_P(
- All,
- MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- testing::Bool());
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- InitialStabilityLogAfterCleanShutDown) {
- base::HistogramTester histogram_tester;
- EnableMetricsReporting();
- // Write a beacon file indicating that Chrome exited cleanly. Note that the
- // crash streak value is arbitrary.
- const base::FilePath beacon_file_path =
- user_data_dir_path().Append(kCleanExitBeaconFilename);
- ASSERT_LT(0,
- base::WriteFile(beacon_file_path,
- CleanExitBeacon::CreateBeaconFileContentsForTesting(
- /*exited_cleanly=*/true, /*crash_streak=*/1)
- .data()));
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(user_data_dir_path()),
- &client, GetLocalState());
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- // No initial stability log should be generated.
- EXPECT_FALSE(service.has_unsent_logs());
- // Ensure that HasPreviousSessionData() is always called on providers,
- // for consistency, even if other conditions already indicate their presence.
- EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
- // The test provider should not have been called upon to provide initial
- // stability nor regular stability metrics.
- EXPECT_FALSE(test_provider->provide_initial_stability_metrics_called());
- EXPECT_FALSE(test_provider->provide_stability_metrics_called());
- // As there wasn't an unclean shutdown, no browser crash samples should have
- // been emitted.
- histogram_tester.ExpectBucketCount("Stability.Counts2",
- StabilityEventType::kBrowserCrash, 0);
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- InitialStabilityLogAtProviderRequest) {
- base::HistogramTester histogram_tester;
- EnableMetricsReporting();
- // Save an existing system profile to prefs, to correspond to what would be
- // saved from a previous session.
- TestMetricsServiceClient client;
- TestMetricsLog log("client", 1, &client);
- DelegatingProvider delegating_provider;
- TestMetricsService::RecordCurrentEnvironmentHelper(&log, GetLocalState(),
- &delegating_provider);
- // Record stability build time and version from previous session, so that
- // stability metrics (including exited cleanly flag) won't be cleared.
- EnvironmentRecorder(GetLocalState())
- .SetBuildtimeAndVersion(MetricsLog::GetBuildTime(),
- client.GetVersionString());
- // Write a beacon file indicating that Chrome exited cleanly. Note that the
- // crash streak value is arbitrary.
- const base::FilePath beacon_file_path =
- user_data_dir_path().Append(kCleanExitBeaconFilename);
- ASSERT_LT(0,
- base::WriteFile(beacon_file_path,
- CleanExitBeacon::CreateBeaconFileContentsForTesting(
- /*exited_cleanly=*/true, /*crash_streak=*/1)
- .data()));
- TestMetricsService service(GetMetricsStateManager(user_data_dir_path()),
- &client, GetLocalState());
- // Add a metrics provider that requests a stability log.
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- test_provider->set_has_initial_stability_metrics(true);
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- // The initial stability log should be generated and persisted in unsent logs.
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- EXPECT_TRUE(test_log_store->has_unsent_logs());
- EXPECT_FALSE(test_log_store->has_staged_log());
- // Ensure that HasPreviousSessionData() is always called on providers,
- // for consistency, even if other conditions already indicate their presence.
- EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
- // The test provider should have been called upon to provide initial
- // stability and regular stability metrics.
- EXPECT_TRUE(test_provider->provide_initial_stability_metrics_called());
- EXPECT_TRUE(test_provider->provide_stability_metrics_called());
- // Stage the log and retrieve it.
- test_log_store->StageNextLog();
- EXPECT_TRUE(test_log_store->has_staged_log());
- ChromeUserMetricsExtension uma_log;
- EXPECT_TRUE(DecodeLogDataToProto(test_log_store->staged_log(), &uma_log));
- EXPECT_TRUE(uma_log.has_client_id());
- EXPECT_TRUE(uma_log.has_session_id());
- EXPECT_TRUE(uma_log.has_system_profile());
- EXPECT_EQ(0, uma_log.user_action_event_size());
- EXPECT_EQ(0, uma_log.omnibox_event_size());
- EXPECT_EQ(0, uma_log.perf_data_size());
- CheckForNonStabilityHistograms(uma_log);
- // As there wasn't an unclean shutdown, no browser crash samples should have
- // been emitted.
- histogram_tester.ExpectBucketCount("Stability.Counts2",
- StabilityEventType::kBrowserCrash, 0);
- }
- INSTANTIATE_TEST_SUITE_P(
- All,
- MetricsServiceTestWithStartupVisibility,
- ::testing::Values(
- StartupVisibilityTestParams{
- .test_name = "UnknownVisibility",
- .startup_visibility = StartupVisibility::kUnknown,
- .consolidate_initial_log_logic = false,
- .expected_beacon_value = true},
- StartupVisibilityTestParams{
- .test_name = "BackgroundVisibility",
- .startup_visibility = StartupVisibility::kBackground,
- .consolidate_initial_log_logic = false,
- .expected_beacon_value = true},
- StartupVisibilityTestParams{
- .test_name = "ForegroundVisibility",
- .startup_visibility = StartupVisibility::kForeground,
- .consolidate_initial_log_logic = false,
- .expected_beacon_value = false},
- StartupVisibilityTestParams{
- .test_name = "UnknownVisibilityConsolidateInitialLogLogic",
- .startup_visibility = StartupVisibility::kUnknown,
- .consolidate_initial_log_logic = true,
- .expected_beacon_value = true},
- StartupVisibilityTestParams{
- .test_name = "BackgroundVisibilityConsolidateInitialLogLogic",
- .startup_visibility = StartupVisibility::kBackground,
- .consolidate_initial_log_logic = true,
- .expected_beacon_value = true},
- StartupVisibilityTestParams{
- .test_name = "ForegroundVisibilityConsolidateInitialLogLogic",
- .startup_visibility = StartupVisibility::kForeground,
- .consolidate_initial_log_logic = true,
- .expected_beacon_value = false}),
- [](const ::testing::TestParamInfo<StartupVisibilityTestParams>& params) {
- return params.param.test_name;
- });
- TEST_P(MetricsServiceTestWithStartupVisibility, InitialStabilityLogAfterCrash) {
- base::HistogramTester histogram_tester;
- PrefService* local_state = GetLocalState();
- EnableMetricsReporting();
- // Write a beacon file indicating that Chrome exited uncleanly. Note that the
- // crash streak value is arbitrary.
- const base::FilePath beacon_file_path =
- user_data_dir_path().Append(kCleanExitBeaconFilename);
- ASSERT_LT(0,
- base::WriteFile(beacon_file_path,
- CleanExitBeacon::CreateBeaconFileContentsForTesting(
- /*exited_cleanly=*/false, /*crash_streak=*/1)
- .data()));
- // Set up prefs to simulate restarting after a crash.
- // Save an existing system profile to prefs, to correspond to what would be
- // saved from a previous session.
- TestMetricsServiceClient client;
- const std::string kCrashedVersion = "4.0.321.0-64-devel";
- client.set_version_string(kCrashedVersion);
- TestMetricsLog log("client", 1, &client);
- DelegatingProvider delegating_provider;
- TestMetricsService::RecordCurrentEnvironmentHelper(&log, local_state,
- &delegating_provider);
- // Record stability build time and version from previous session, so that
- // stability metrics (including exited cleanly flag) won't be cleared.
- EnvironmentRecorder(local_state)
- .SetBuildtimeAndVersion(MetricsLog::GetBuildTime(),
- client.GetVersionString());
- const std::string kCurrentVersion = "5.0.322.0-64-devel";
- client.set_version_string(kCurrentVersion);
- StartupVisibilityTestParams params = GetParam();
- TestMetricsService service(
- GetMetricsStateManager(user_data_dir_path(), params.startup_visibility),
- &client, local_state);
- // Add a provider.
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- // Verify that Chrome is (or is not) watching for crashes by checking the
- // beacon value.
- std::string beacon_file_contents;
- ASSERT_TRUE(base::ReadFileToString(beacon_file_path, &beacon_file_contents));
- std::string partial_expected_contents;
- #if BUILDFLAG(IS_ANDROID)
- // Whether Chrome is watching for crashes after
- // InitializeMetricsRecordingState() depends on the type of Android Chrome
- // session. See the comments in MetricsService::InitializeMetricsState() for
- // more details.
- const std::string beacon_value =
- params.expected_beacon_value ? "true" : "false";
- partial_expected_contents = "exited_cleanly\":" + beacon_value;
- #else
- partial_expected_contents = "exited_cleanly\":false";
- #endif // BUILDFLAG(IS_ANDROID)
- EXPECT_TRUE(base::Contains(beacon_file_contents, partial_expected_contents));
- // The initial stability log should be generated and persisted in unsent logs.
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- EXPECT_TRUE(test_log_store->has_unsent_logs());
- EXPECT_FALSE(test_log_store->has_staged_log());
- // Ensure that HasPreviousSessionData() is always called on providers,
- // for consistency, even if other conditions already indicate their presence.
- EXPECT_TRUE(test_provider->has_initial_stability_metrics_called());
- // The test provider should have been called upon to provide initial
- // stability and regular stability metrics.
- EXPECT_TRUE(test_provider->provide_initial_stability_metrics_called());
- EXPECT_TRUE(test_provider->provide_stability_metrics_called());
- // Stage the log and retrieve it.
- test_log_store->StageNextLog();
- EXPECT_TRUE(test_log_store->has_staged_log());
- ChromeUserMetricsExtension uma_log;
- EXPECT_TRUE(DecodeLogDataToProto(test_log_store->staged_log(), &uma_log));
- EXPECT_TRUE(uma_log.has_client_id());
- EXPECT_TRUE(uma_log.has_session_id());
- EXPECT_TRUE(uma_log.has_system_profile());
- EXPECT_EQ(0, uma_log.user_action_event_size());
- EXPECT_EQ(0, uma_log.omnibox_event_size());
- EXPECT_EQ(0, uma_log.perf_data_size());
- CheckForNonStabilityHistograms(uma_log);
- EXPECT_EQ(kCrashedVersion, uma_log.system_profile().app_version());
- EXPECT_EQ(kCurrentVersion,
- uma_log.system_profile().log_written_by_app_version());
- histogram_tester.ExpectBucketCount("Stability.Counts2",
- StabilityEventType::kBrowserCrash, 1);
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- InitialLogsHaveOnDidCreateMetricsLogHistograms) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- // Create a provider that will log to |kOnDidCreateMetricsLogHistogramName|
- // in OnDidCreateMetricsLog()
- auto* test_provider = new TestMetricsProviderForOnDidCreateMetricsLog();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- // Start() will create the first ongoing log.
- service.Start();
- ASSERT_EQ(TestMetricsService::INIT_TASK_SCHEDULED, service.state());
- // Run pending tasks to finish init task and complete the first ongoing log.
- task_runner_->RunPendingTasks();
- ASSERT_EQ(TestMetricsService::SENDING_LOGS, service.state());
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- // Stage the next log, which should be the first ongoing log.
- // Check that it has one sample in |kOnDidCreateMetricsLogHistogramName|.
- test_log_store->StageNextLog();
- EXPECT_EQ(1, GetSampleCountOfOnDidCreateLogHistogram(test_log_store));
- // Discard the staged log and close and stage the next log, which is the
- // second "ongoing log".
- // Check that it has one sample in |kOnDidCreateMetricsLogHistogramName|.
- test_log_store->DiscardStagedLog();
- service.StageCurrentLogForTest();
- EXPECT_EQ(1, GetSampleCountOfOnDidCreateLogHistogram(test_log_store));
- // Check one more log for good measure.
- test_log_store->DiscardStagedLog();
- service.StageCurrentLogForTest();
- EXPECT_EQ(1, GetSampleCountOfOnDidCreateLogHistogram(test_log_store));
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- MarkCurrentHistogramsAsReported) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- // Emit to histogram |Test.Before.Histogram|.
- ASSERT_FALSE(HistogramExists("Test.Before.Histogram"));
- base::UmaHistogramBoolean("Test.Before.Histogram", true);
- ASSERT_TRUE(HistogramExists("Test.Before.Histogram"));
- // Mark histogram data that has been collected until now (in particular, the
- // |Test.Before.Histogram| sample) as reported.
- service.MarkCurrentHistogramsAsReported();
- // Emit to histogram |Test.After.Histogram|.
- ASSERT_FALSE(HistogramExists("Test.After.Histogram"));
- base::UmaHistogramBoolean("Test.After.Histogram", true);
- ASSERT_TRUE(HistogramExists("Test.After.Histogram"));
- // Verify that the |Test.Before.Histogram| sample was marked as reported, and
- // is not included in the next snapshot.
- EXPECT_EQ(0, GetHistogramDeltaTotalCount("Test.Before.Histogram"));
- // Verify that the |Test.After.Histogram| sample was not marked as reported,
- // and is included in the next snapshot.
- EXPECT_EQ(1, GetHistogramDeltaTotalCount("Test.After.Histogram"));
- // Clean up histograms.
- base::StatisticsRecorder::ForgetHistogramForTesting("Test.Before.Histogram");
- base::StatisticsRecorder::ForgetHistogramForTesting("Test.After.Histogram");
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- LogHasUserActions) {
- // This test verifies that user actions are properly captured in UMA logs.
- // In particular, it checks that the first log has actions, a behavior that
- // was buggy in the past, plus additional checks for subsequent logs with
- // different numbers of actions. This behavior is only fixed after
- // consolidating the initial log logic.
- if (!ShouldConsolidateInitialLogLogic())
- return;
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- // Start() will create an initial log.
- service.Start();
- ASSERT_EQ(TestMetricsService::INIT_TASK_SCHEDULED, service.state());
- base::RecordAction(base::UserMetricsAction("TestAction"));
- base::RecordAction(base::UserMetricsAction("TestAction"));
- base::RecordAction(base::UserMetricsAction("DifferentAction"));
- // Run pending tasks to finish init task and complete the first ongoing log.
- task_runner_->RunPendingTasks();
- ASSERT_EQ(TestMetricsService::SENDING_LOGS, service.state());
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- // Stage the next log, which should be the initial metrics log.
- test_log_store->StageNextLog();
- EXPECT_EQ(3, GetNumberOfUserActions(test_log_store));
- // Log another action.
- base::RecordAction(base::UserMetricsAction("TestAction"));
- test_log_store->DiscardStagedLog();
- service.StageCurrentLogForTest();
- EXPECT_EQ(1, GetNumberOfUserActions(test_log_store));
- // Check a log with no actions.
- test_log_store->DiscardStagedLog();
- service.StageCurrentLogForTest();
- EXPECT_EQ(0, GetNumberOfUserActions(test_log_store));
- // And another one with a couple.
- base::RecordAction(base::UserMetricsAction("TestAction"));
- base::RecordAction(base::UserMetricsAction("TestAction"));
- test_log_store->DiscardStagedLog();
- service.StageCurrentLogForTest();
- EXPECT_EQ(2, GetNumberOfUserActions(test_log_store));
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- FirstLogCreatedBeforeUnsentLogsSent) {
- // This test checks that we will create and serialize the first ongoing log
- // before starting to send unsent logs from the past session. The latter is
- // simulated by injecting some fake ongoing logs into the MetricsLogStore.
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- // Start() will create the first ongoing log.
- service.Start();
- ASSERT_EQ(TestMetricsService::INIT_TASK_SCHEDULED, service.state());
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- // Set up the log store with an existing fake log entry. The string content
- // is never deserialized to proto, so we're just passing some dummy content.
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(0u, test_log_store->ongoing_log_count());
- test_log_store->StoreLog("blah_blah", MetricsLog::ONGOING_LOG, LogMetadata());
- // Note: |initial_log_count()| refers to initial stability logs, so the above
- // log is counted an ongoing log (per its type).
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(1u, test_log_store->ongoing_log_count());
- // Run pending tasks to finish init task and complete the first ongoing log.
- task_runner_->RunPendingTasks();
- ASSERT_EQ(TestMetricsService::SENDING_LOGS, service.state());
- // When the init task is complete, the first ongoing log should be created
- // and added to the ongoing logs.
- EXPECT_EQ(0u, test_log_store->initial_log_count());
- EXPECT_EQ(2u, test_log_store->ongoing_log_count());
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- MetricsProviderOnRecordingDisabledCalledOnInitialStop) {
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- service.Stop();
- EXPECT_TRUE(test_provider->on_recording_disabled_called());
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- MetricsProvidersInitialized) {
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- EXPECT_TRUE(test_provider->init_called());
- }
- // Verify that FieldTrials activated by a MetricsProvider are reported by the
- // FieldTrialsProvider.
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- ActiveFieldTrialsReported) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- // Set up FieldTrials.
- const std::string trial_name1 = "CoffeeExperiment";
- const std::string group_name1 = "Free";
- base::FieldTrial* trial1 =
- base::FieldTrialList::CreateFieldTrial(trial_name1, group_name1);
- const std::string trial_name2 = "DonutExperiment";
- const std::string group_name2 = "MapleBacon";
- base::FieldTrial* trial2 =
- base::FieldTrialList::CreateFieldTrial(trial_name2, group_name2);
- service.RegisterMetricsProvider(
- std::make_unique<ExperimentTestMetricsProvider>(trial1, trial2));
- service.InitializeMetricsRecordingState();
- service.Start();
- service.StageCurrentLogForTest();
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- ChromeUserMetricsExtension uma_log;
- EXPECT_TRUE(DecodeLogDataToProto(test_log_store->staged_log(), &uma_log));
- // Verify that the reported FieldTrial IDs are for the trial set up by this
- // test.
- EXPECT_TRUE(
- IsFieldTrialPresent(uma_log.system_profile(), trial_name1, group_name1));
- EXPECT_TRUE(
- IsFieldTrialPresent(uma_log.system_profile(), trial_name2, group_name2));
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- SystemProfileDataProvidedOnEnableRecording) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- TestMetricsProvider* test_provider = new TestMetricsProvider();
- service.RegisterMetricsProvider(
- std::unique_ptr<MetricsProvider>(test_provider));
- service.InitializeMetricsRecordingState();
- // ProvideSystemProfileMetrics() shouldn't be called initially.
- EXPECT_FALSE(test_provider->provide_system_profile_metrics_called());
- EXPECT_FALSE(service.persistent_system_profile_provided());
- service.Start();
- // Start should call ProvideSystemProfileMetrics().
- EXPECT_TRUE(test_provider->provide_system_profile_metrics_called());
- EXPECT_TRUE(service.persistent_system_profile_provided());
- EXPECT_FALSE(service.persistent_system_profile_complete());
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature, SplitRotation) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- service.Start();
- // Rotation loop should create a log and mark state as idle.
- // Upload loop should start upload or be restarted.
- // The independent-metrics upload job will be started and always be a task.
- task_runner_->RunPendingTasks();
- // Rotation loop should terminated due to being idle.
- // Upload loop should start uploading if it isn't already.
- task_runner_->RunPendingTasks();
- EXPECT_TRUE(client.uploader()->is_uploading());
- EXPECT_EQ(1U, task_runner_->NumPendingTasks());
- service.OnApplicationNotIdle();
- EXPECT_TRUE(client.uploader()->is_uploading());
- EXPECT_EQ(2U, task_runner_->NumPendingTasks());
- // Log generation should be suppressed due to unsent log.
- // Idle state should not be reset.
- task_runner_->RunPendingTasks();
- EXPECT_TRUE(client.uploader()->is_uploading());
- EXPECT_EQ(2U, task_runner_->NumPendingTasks());
- // Make sure idle state was not reset.
- task_runner_->RunPendingTasks();
- EXPECT_TRUE(client.uploader()->is_uploading());
- EXPECT_EQ(2U, task_runner_->NumPendingTasks());
- // Upload should not be rescheduled, since there are no other logs.
- client.uploader()->CompleteUpload(200);
- EXPECT_FALSE(client.uploader()->is_uploading());
- EXPECT_EQ(2U, task_runner_->NumPendingTasks());
- // Running should generate a log, restart upload loop, and mark idle.
- task_runner_->RunPendingTasks();
- EXPECT_FALSE(client.uploader()->is_uploading());
- EXPECT_EQ(3U, task_runner_->NumPendingTasks());
- // Upload should start, and rotation loop should idle out.
- task_runner_->RunPendingTasks();
- EXPECT_TRUE(client.uploader()->is_uploading());
- EXPECT_EQ(1U, task_runner_->NumPendingTasks());
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- LastLiveTimestamp) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- base::Time initial_last_live_time =
- GetLocalState()->GetTime(prefs::kStabilityBrowserLastLiveTimeStamp);
- service.InitializeMetricsRecordingState();
- service.Start();
- task_runner_->RunPendingTasks();
- size_t num_pending_tasks = task_runner_->NumPendingTasks();
- service.StartUpdatingLastLiveTimestamp();
- // Starting the update sequence should not write anything, but should
- // set up for a later write.
- EXPECT_EQ(
- initial_last_live_time,
- GetLocalState()->GetTime(prefs::kStabilityBrowserLastLiveTimeStamp));
- EXPECT_EQ(num_pending_tasks + 1, task_runner_->NumPendingTasks());
- // To avoid flakiness, yield until we're over a microsecond threshold.
- YieldUntil(initial_last_live_time + base::Microseconds(2));
- task_runner_->RunPendingTasks();
- // Verify that the time has updated in local state.
- base::Time updated_last_live_time =
- GetLocalState()->GetTime(prefs::kStabilityBrowserLastLiveTimeStamp);
- EXPECT_LT(initial_last_live_time, updated_last_live_time);
- // Double check that an update schedules again...
- YieldUntil(updated_last_live_time + base::Microseconds(2));
- task_runner_->RunPendingTasks();
- EXPECT_LT(
- updated_last_live_time,
- GetLocalState()->GetTime(prefs::kStabilityBrowserLastLiveTimeStamp));
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- EnablementObserverNotification) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- absl::optional<bool> enabled;
- auto observer = [&enabled](bool notification) { enabled = notification; };
- auto subscription =
- service.AddEnablementObserver(base::BindLambdaForTesting(observer));
- service.Start();
- ASSERT_TRUE(enabled.has_value());
- EXPECT_TRUE(enabled.value());
- enabled.reset();
- service.Stop();
- ASSERT_TRUE(enabled.has_value());
- EXPECT_FALSE(enabled.value());
- }
- #if BUILDFLAG(IS_CHROMEOS_LACROS)
- // ResetClientId is only enabled on certain targets.
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- SetClientIdToExternalId) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- const std::string client_id = "d92ad666-a420-4c73-8718-94311ae2ff5f";
- EXPECT_NE(service.GetClientId(), client_id);
- service.SetExternalClientId(client_id);
- // Reset will cause the client id to be regenerated. If an external client id
- // is provided, it should defer to using that id instead of creating its own.
- service.ResetClientId();
- EXPECT_EQ(service.GetClientId(), client_id);
- }
- #endif // BUILDFLAG(IS_CHROMEOS_LACROS)
- #if BUILDFLAG(IS_CHROMEOS_ASH)
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- OngoingLogNotFlushedBeforeInitialLogWhenUserLogStoreSet) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- // Start() will create the first ongoing log.
- service.Start();
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
- InitializeTestLogStoreAndGet();
- TestUnsentLogStore* alternate_ongoing_log_store_ptr =
- alternate_ongoing_log_store.get();
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(0u, test_log_store->ongoing_log_count());
- service.SetUserLogStore(std::move(alternate_ongoing_log_store));
- // Initial logs should not have been collected so the ongoing log being
- // recorded should not be flushed when a user log store is mounted.
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(0u, test_log_store->ongoing_log_count());
- // Run pending tasks to finish init task and complete the first ongoing log.
- task_runner_->RunPendingTasks();
- ASSERT_EQ(TestMetricsService::SENDING_LOGS, service.state());
- // When the init task is complete, the first ongoing log should be created
- // in the alternate ongoing log store.
- EXPECT_EQ(0u, test_log_store->initial_log_count());
- EXPECT_EQ(0u, test_log_store->ongoing_log_count());
- EXPECT_EQ(1u, alternate_ongoing_log_store_ptr->size());
- }
- TEST_P(MetricsServiceTestWithConsolidateInitialLogLogicFeature,
- OngoingLogFlushedAfterInitialLogWhenUserLogStoreSet) {
- EnableMetricsReporting();
- TestMetricsServiceClient client;
- TestMetricsService service(GetMetricsStateManager(), &client,
- GetLocalState());
- service.InitializeMetricsRecordingState();
- // Start() will create the first ongoing log.
- service.Start();
- MetricsLogStore* test_log_store = service.LogStoreForTest();
- std::unique_ptr<TestUnsentLogStore> alternate_ongoing_log_store =
- InitializeTestLogStoreAndGet();
- // Init state.
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(0u, test_log_store->ongoing_log_count());
- // Run pending tasks to finish init task and complete the first ongoing log.
- task_runner_->RunPendingTasks();
- ASSERT_EQ(TestMetricsService::SENDING_LOGS, service.state());
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(1u, test_log_store->ongoing_log_count());
- // User log store set post-init.
- service.SetUserLogStore(std::move(alternate_ongoing_log_store));
- // Another log should have been flushed from setting the user log store.
- ASSERT_EQ(0u, test_log_store->initial_log_count());
- ASSERT_EQ(2u, test_log_store->ongoing_log_count());
- }
- #endif
- } // namespace metrics
|