1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/metrics_log.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <string>
11
12 #include "base/base64.h"
13 #include "base/command_line.h"
14 #include "base/memory/ptr_util.h"
15 #include "base/metrics/bucket_ranges.h"
16 #include "base/metrics/sample_vector.h"
17 #include "base/strings/strcat.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h"
20 #include "base/system/sys_info.h"
21 #include "base/test/simple_test_clock.h"
22 #include "base/test/simple_test_tick_clock.h"
23 #include "base/test/task_environment.h"
24 #include "base/time/default_clock.h"
25 #include "base/time/default_tick_clock.h"
26 #include "base/time/time.h"
27 #include "build/build_config.h"
28 #include "build/chromeos_buildflags.h"
29 #include "components/metrics/cpu_metrics_provider.h"
30 #include "components/metrics/delegating_provider.h"
31 #include "components/metrics/environment_recorder.h"
32 #include "components/metrics/metrics_pref_names.h"
33 #include "components/metrics/metrics_state_manager.h"
34 #include "components/metrics/test/test_metrics_provider.h"
35 #include "components/metrics/test/test_metrics_service_client.h"
36 #include "components/network_time/network_time_test_utils.h"
37 #include "components/prefs/pref_service.h"
38 #include "components/prefs/testing_pref_service.h"
39 #include "components/variations/active_field_trials.h"
40 #include "services/network/test/test_shared_url_loader_factory.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
43
44 #if BUILDFLAG(IS_ANDROID)
45 #include "base/android/build_info.h"
46 #endif
47
48 #if BUILDFLAG(IS_WIN)
49 #include "base/win/current_module.h"
50 #endif
51
52 #if BUILDFLAG(IS_LINUX)
53 #include "base/nix/xdg_util.h"
54 #include "base/scoped_environment_variable_override.h"
55 #endif
56
57 namespace metrics {
58 namespace {
59
60 const char kClientId[] = "0a94430b-18e5-43c8-a657-580f7e855ce1";
61 const int kSessionId = 127;
62
63 class TestMetricsLog : public MetricsLog {
64 public:
TestMetricsLog(const std::string & client_id,int session_id,LogType log_type,MetricsServiceClient * client)65 TestMetricsLog(const std::string& client_id,
66 int session_id,
67 LogType log_type,
68 MetricsServiceClient* client)
69 : MetricsLog(client_id, session_id, log_type, client) {}
70
71 TestMetricsLog(const TestMetricsLog&) = delete;
72 TestMetricsLog& operator=(const TestMetricsLog&) = delete;
73
~TestMetricsLog()74 ~TestMetricsLog() override {}
75
uma_proto() const76 const ChromeUserMetricsExtension& uma_proto() const {
77 return *MetricsLog::uma_proto();
78 }
79
mutable_uma_proto()80 ChromeUserMetricsExtension* mutable_uma_proto() {
81 return MetricsLog::uma_proto();
82 }
83
system_profile() const84 const SystemProfileProto& system_profile() const {
85 return uma_proto().system_profile();
86 }
87 };
88
89 // Returns the expected hardware class for a metrics log.
GetExpectedHardwareClass()90 std::string GetExpectedHardwareClass() {
91 #if BUILDFLAG(IS_CHROMEOS_ASH)
92 // Currently, we are relying on base/ implementation for functionality on our
93 // side which can be fragile if in the future someone decides to change that.
94 // This replicates the logic to get the hardware class for ChromeOS and this
95 // result should match with the result by calling
96 // base::SysInfo::HardwareModelName().
97 std::string board = base::SysInfo::GetLsbReleaseBoard();
98 if (board == "unknown") {
99 return "";
100 }
101 const size_t index = board.find("-signed-");
102 if (index != std::string::npos)
103 board.resize(index);
104 return base::ToUpperASCII(board);
105 #else
106 return base::SysInfo::HardwareModelName();
107 #endif
108 }
109
110 // Sets the time in |network_time| to |time|.
UpdateNetworkTime(network_time::NetworkTimeTracker * network_time_tracker,base::TickClock * tick_clock,base::Time time)111 void UpdateNetworkTime(network_time::NetworkTimeTracker* network_time_tracker,
112 base::TickClock* tick_clock,
113 base::Time time) {
114 network_time_tracker->UpdateNetworkTime(
115 time,
116 base::Seconds(1), // resolution
117 base::Milliseconds(250), // latency
118 tick_clock->NowTicks()); // posting time
119 }
120
121 } // namespace
122
123 class MetricsLogTest : public testing::Test {
124 public:
MetricsLogTest()125 MetricsLogTest() { MetricsLog::RegisterPrefs(prefs_.registry()); }
126
127 MetricsLogTest(const MetricsLogTest&) = delete;
128 MetricsLogTest& operator=(const MetricsLogTest&) = delete;
129
~MetricsLogTest()130 ~MetricsLogTest() override {}
131
132 protected:
133 // Check that the values in |system_values| are filled in and expected ones
134 // correspond to the test data defined at the top of this file.
CheckSystemProfile(const SystemProfileProto & system_profile)135 void CheckSystemProfile(const SystemProfileProto& system_profile) {
136 // Check for presence of core system profile fields.
137 EXPECT_TRUE(system_profile.has_build_timestamp());
138 EXPECT_TRUE(system_profile.has_app_version());
139 EXPECT_TRUE(system_profile.has_channel());
140 EXPECT_FALSE(system_profile.has_is_extended_stable_channel());
141 EXPECT_TRUE(system_profile.has_application_locale());
142 EXPECT_TRUE(system_profile.has_client_uuid());
143
144 const SystemProfileProto::OS& os = system_profile.os();
145 EXPECT_TRUE(os.has_name());
146 EXPECT_TRUE(os.has_version());
147
148 // Check matching test brand code.
149 EXPECT_EQ(TestMetricsServiceClient::kBrandForTesting,
150 system_profile.brand_code());
151
152 // Check for presence of fields set by a metrics provider.
153 const SystemProfileProto::Hardware& hardware = system_profile.hardware();
154 EXPECT_EQ(hardware.hardware_class(), GetExpectedHardwareClass());
155 EXPECT_TRUE(hardware.has_cpu());
156 EXPECT_TRUE(hardware.cpu().has_vendor_name());
157 EXPECT_TRUE(hardware.cpu().has_signature());
158 EXPECT_TRUE(hardware.cpu().has_num_cores());
159
160 // TODO(isherman): Verify other data written into the protobuf as a result
161 // of this call.
162 }
163
164 TestMetricsServiceClient client_;
165 TestingPrefServiceSimple prefs_;
166 };
167
TEST_F(MetricsLogTest,FinalizedRecordId)168 TEST_F(MetricsLogTest, FinalizedRecordId) {
169 MetricsLog log1(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
170 MetricsLog log2(kClientId, kSessionId, MetricsLog::INDEPENDENT_LOG, &client_);
171 MetricsLog log3(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
172 &client_);
173
174 ASSERT_FALSE(log1.uma_proto()->has_finalized_record_id());
175 ASSERT_FALSE(log2.uma_proto()->has_finalized_record_id());
176 ASSERT_FALSE(log3.uma_proto()->has_finalized_record_id());
177
178 // Set an initial finalized record-id value in prefs, so test values are
179 // predictable.
180 prefs_.SetInteger(prefs::kMetricsLogFinalizedRecordId, 500);
181
182 log1.AssignFinalizedRecordId(&prefs_);
183 log2.AssignFinalizedRecordId(&prefs_);
184 log3.AssignFinalizedRecordId(&prefs_);
185
186 EXPECT_EQ(501, log1.uma_proto()->finalized_record_id());
187 EXPECT_EQ(502, log2.uma_proto()->finalized_record_id());
188 EXPECT_EQ(503, log3.uma_proto()->finalized_record_id());
189 }
190
TEST_F(MetricsLogTest,RecordId)191 TEST_F(MetricsLogTest, RecordId) {
192 MetricsLog log1(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
193 MetricsLog log2(kClientId, kSessionId, MetricsLog::INDEPENDENT_LOG, &client_);
194 MetricsLog log3(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
195 &client_);
196
197 ASSERT_FALSE(log1.uma_proto()->has_record_id());
198 ASSERT_FALSE(log2.uma_proto()->has_record_id());
199 ASSERT_FALSE(log3.uma_proto()->has_record_id());
200
201 // Set an initial record-id value in prefs, so test values are predictable.
202 prefs_.SetInteger(prefs::kMetricsLogRecordId, 500);
203
204 log1.AssignRecordId(&prefs_);
205 log2.AssignRecordId(&prefs_);
206 log3.AssignRecordId(&prefs_);
207
208 EXPECT_EQ(501, log1.uma_proto()->record_id());
209 EXPECT_EQ(502, log2.uma_proto()->record_id());
210 EXPECT_EQ(503, log3.uma_proto()->record_id());
211 }
212
TEST_F(MetricsLogTest,SessionHash)213 TEST_F(MetricsLogTest, SessionHash) {
214 MetricsLog log1(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
215 MetricsLog log2(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
216
217 // Verify that created logs are tagged with the same session hash.
218 EXPECT_TRUE(log1.uma_proto()->system_profile().has_session_hash());
219 EXPECT_TRUE(log2.uma_proto()->system_profile().has_session_hash());
220 EXPECT_EQ(log1.uma_proto()->system_profile().session_hash(),
221 log2.uma_proto()->system_profile().session_hash());
222 }
223
TEST_F(MetricsLogTest,LogType)224 TEST_F(MetricsLogTest, LogType) {
225 MetricsLog log1(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
226 EXPECT_EQ(MetricsLog::ONGOING_LOG, log1.log_type());
227
228 MetricsLog log2(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
229 &client_);
230 EXPECT_EQ(MetricsLog::INITIAL_STABILITY_LOG, log2.log_type());
231 }
232
TEST_F(MetricsLogTest,BasicRecord)233 TEST_F(MetricsLogTest, BasicRecord) {
234 client_.set_version_string("bogus version");
235 const std::string kOtherClientId = "0a94430b-18e5-43c8-a657-580f7e855ce2";
236 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
237 // Clears existing command line flags and sets mock flags:
238 // "--mock-flag-1 --mock-flag-2=unused_value"
239 // Hashes of these flags should be populated on the system_profile field.
240 command_line->InitFromArgv(0, nullptr);
241 command_line->AppendSwitch("mock-flag-1");
242 command_line->AppendSwitchASCII("mock-flag-2", "unused_value");
243
244 #if BUILDFLAG(IS_LINUX)
245 base::ScopedEnvironmentVariableOverride scoped_desktop_override(
246 base::nix::kXdgCurrentDesktopEnvVar, "GNOME");
247 metrics::SystemProfileProto::OS::XdgCurrentDesktop expected_current_desktop =
248 metrics::SystemProfileProto::OS::GNOME;
249
250 base::ScopedEnvironmentVariableOverride scoped_session_override(
251 base::nix::kXdgSessionTypeEnvVar, "wayland");
252 metrics::SystemProfileProto::OS::XdgSessionType expected_session_type =
253 metrics::SystemProfileProto::OS::WAYLAND;
254 #endif
255
256 MetricsLog log(kOtherClientId, 137, MetricsLog::ONGOING_LOG, &client_);
257
258 std::string encoded;
259 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
260 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
261
262 // A couple of fields are hard to mock, so these will be copied over directly
263 // for the expected output.
264 ChromeUserMetricsExtension parsed;
265 ASSERT_TRUE(parsed.ParseFromString(encoded));
266
267 ChromeUserMetricsExtension expected;
268 expected.set_client_id(13917849739535108017ull); // Hashed kOtherClientId
269 expected.set_session_id(137);
270
271 SystemProfileProto* system_profile = expected.mutable_system_profile();
272 system_profile->set_app_version("bogus version");
273 // Make sure |client_uuid| in the system profile is the unhashed client id
274 // and is the same as the client id in |local_prefs|.
275 system_profile->set_client_uuid(kOtherClientId);
276 system_profile->set_channel(client_.GetChannel());
277 system_profile->set_application_locale(client_.GetApplicationLocale());
278 system_profile->set_brand_code(TestMetricsServiceClient::kBrandForTesting);
279 // Hashes of "mock-flag-1" and "mock-flag-2" from SetUpCommandLine.
280 system_profile->add_command_line_key_hash(2578836236);
281 system_profile->add_command_line_key_hash(2867288449);
282 // The session hash.
283 system_profile->set_session_hash(
284 log.uma_proto()->system_profile().session_hash());
285
286 #if defined(ADDRESS_SANITIZER) || DCHECK_IS_ON()
287 system_profile->set_is_instrumented_build(true);
288 #endif
289 metrics::SystemProfileProto::Hardware* hardware =
290 system_profile->mutable_hardware();
291 hardware->set_cpu_architecture(base::SysInfo::OperatingSystemArchitecture());
292 auto app_os_arch = base::SysInfo::ProcessCPUArchitecture();
293 if (!app_os_arch.empty())
294 hardware->set_app_cpu_architecture(app_os_arch);
295 hardware->set_system_ram_mb(base::SysInfo::AmountOfPhysicalMemoryMB());
296 hardware->set_hardware_class(GetExpectedHardwareClass());
297 #if BUILDFLAG(IS_WIN)
298 hardware->set_dll_base(reinterpret_cast<uint64_t>(CURRENT_MODULE()));
299 #endif
300
301 #if BUILDFLAG(IS_CHROMEOS_LACROS)
302 system_profile->mutable_os()->set_name("Lacros");
303 #elif BUILDFLAG(IS_CHROMEOS_ASH)
304 system_profile->mutable_os()->set_name("CrOS");
305 #else
306 system_profile->mutable_os()->set_name(base::SysInfo::OperatingSystemName());
307 #endif
308 system_profile->mutable_os()->set_version(
309 base::SysInfo::OperatingSystemVersion());
310 #if BUILDFLAG(IS_CHROMEOS_ASH)
311 system_profile->mutable_os()->set_kernel_version(
312 base::SysInfo::KernelVersion());
313 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
314 system_profile->mutable_os()->set_kernel_version(
315 base::SysInfo::OperatingSystemVersion());
316 #elif BUILDFLAG(IS_ANDROID)
317 system_profile->mutable_os()->set_build_fingerprint(
318 base::android::BuildInfo::GetInstance()->android_build_fp());
319 system_profile->set_app_package_name("test app");
320 #elif BUILDFLAG(IS_IOS)
321 system_profile->mutable_os()->set_build_number(
322 base::SysInfo::GetIOSBuildNumber());
323 #endif
324
325 #if BUILDFLAG(IS_LINUX)
326 system_profile->mutable_os()->set_xdg_session_type(expected_session_type);
327 system_profile->mutable_os()->set_xdg_current_desktop(
328 expected_current_desktop);
329 #endif
330
331 // Hard to mock.
332 system_profile->set_build_timestamp(
333 parsed.system_profile().build_timestamp());
334 #if BUILDFLAG(IS_ANDROID)
335 system_profile->set_installer_package(
336 parsed.system_profile().installer_package());
337 #endif
338
339 // Not tested here; instead tested in Timestamps_* tests below.
340 expected.mutable_time_log_created()->CopyFrom(parsed.time_log_created());
341 expected.mutable_time_log_closed()->CopyFrom(parsed.time_log_closed());
342
343 EXPECT_EQ(expected.SerializeAsString(), encoded);
344 }
345
TEST_F(MetricsLogTest,FinalizeLog)346 TEST_F(MetricsLogTest, FinalizeLog) {
347 static const char kVersionString[] = "1";
348 static const char kNewVersionString[] = "2";
349 client_.set_version_string(kVersionString);
350
351 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
352 TestMetricsLog log2(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
353
354 // Fill logs with user actions and omnibox events. We put more than the limit
355 // to verify that when calling FinalizeLog(), we may optionally truncate
356 // those events.
357 const int kUserActionCount = internal::kUserActionEventLimit * 2;
358 for (int i = 0; i < kUserActionCount; ++i) {
359 log.RecordUserAction("BasicAction", base::TimeTicks::Now());
360 log2.RecordUserAction("BasicAction", base::TimeTicks::Now());
361 }
362 const int kOmniboxEventCount = internal::kOmniboxEventLimit * 2;
363 for (int i = 0; i < kOmniboxEventCount; ++i) {
364 // Add an empty omnibox event. Not fully realistic since these are normally
365 // supplied by a metrics provider.
366 log.mutable_uma_proto()->add_omnibox_event();
367 log2.mutable_uma_proto()->add_omnibox_event();
368 }
369
370 // Finalize |log|. We truncate events, and we pass the same version string as
371 // the one that was used when the log was created.
372 std::string encoded;
373 log.FinalizeLog(/*truncate_events=*/true, client_.GetVersionString(),
374 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
375
376 // Finalize |log2|. We do not truncate events, and we pass a different version
377 // string than the one that was used when the log was created.
378 client_.set_version_string(kNewVersionString);
379 std::string encoded2;
380 log2.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
381 log.GetCurrentClockTime(/*record_time_zone=*/true),
382 &encoded2);
383
384 ChromeUserMetricsExtension parsed;
385 parsed.ParseFromString(encoded);
386 ChromeUserMetricsExtension parsed2;
387 parsed2.ParseFromString(encoded2);
388
389 // The user actions and omnibox events in |parsed| should have been truncated
390 // to the limits, while |parsed2| should be untouched.
391 EXPECT_EQ(parsed.user_action_event_size(), internal::kUserActionEventLimit);
392 EXPECT_EQ(parsed.omnibox_event_size(), internal::kOmniboxEventLimit);
393 EXPECT_EQ(parsed2.user_action_event_size(), kUserActionCount);
394 EXPECT_EQ(parsed2.omnibox_event_size(), kOmniboxEventCount);
395
396 // |kNewVersionString| (the version string when |log2| was closed) should
397 // have been written to |parsed2| since it differs from |kVersionString|
398 // (the version string when |log2| was created). |parsed| should not have it
399 // since the version strings were the same.
400 EXPECT_EQ(parsed2.system_profile().app_version(), kVersionString);
401 EXPECT_EQ(parsed2.system_profile().log_written_by_app_version(),
402 kNewVersionString);
403 EXPECT_EQ(parsed.system_profile().app_version(), kVersionString);
404 EXPECT_FALSE(parsed.system_profile().has_log_written_by_app_version());
405 }
406
TEST_F(MetricsLogTest,Timestamps_InitialStabilityLog)407 TEST_F(MetricsLogTest, Timestamps_InitialStabilityLog) {
408 std::unique_ptr<base::SimpleTestClock> clock =
409 std::make_unique<base::SimpleTestClock>();
410
411 // Should not have times from initial stability logs.
412 clock->SetNow(base::Time::FromTimeT(1));
413 MetricsLog log(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
414 clock.get(), nullptr, &client_);
415 clock->SetNow(base::Time::FromTimeT(2));
416 std::string encoded;
417 // Don't set the close_time param since this is an initial stability log.
418 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
419 /*close_time=*/std::nullopt, &encoded);
420 ChromeUserMetricsExtension parsed;
421 ASSERT_TRUE(parsed.ParseFromString(encoded));
422 EXPECT_FALSE(parsed.has_time_log_created());
423 EXPECT_FALSE(parsed.has_time_log_closed());
424 }
425
TEST_F(MetricsLogTest,Timestamps_IndependentLog)426 TEST_F(MetricsLogTest, Timestamps_IndependentLog) {
427 std::unique_ptr<base::SimpleTestClock> clock =
428 std::make_unique<base::SimpleTestClock>();
429
430 // Should not have times from independent logs.
431 clock->SetNow(base::Time::FromTimeT(1));
432 MetricsLog log(kClientId, kSessionId, MetricsLog::INDEPENDENT_LOG,
433 clock.get(), nullptr, &client_);
434 clock->SetNow(base::Time::FromTimeT(2));
435 std::string encoded;
436 // Don't set the close_time param since this is an independent log.
437 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
438 /*close_time=*/std::nullopt, &encoded);
439 ChromeUserMetricsExtension parsed;
440 ASSERT_TRUE(parsed.ParseFromString(encoded));
441 EXPECT_FALSE(parsed.has_time_log_created());
442 EXPECT_FALSE(parsed.has_time_log_closed());
443 }
444
TEST_F(MetricsLogTest,Timestamps_OngoingLog)445 TEST_F(MetricsLogTest, Timestamps_OngoingLog) {
446 std::unique_ptr<base::SimpleTestClock> clock =
447 std::make_unique<base::SimpleTestClock>();
448
449 // Should have times from regular (ongoing) logs.
450 clock->SetNow(base::Time::FromTimeT(1));
451 MetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, clock.get(),
452 nullptr, &client_);
453 clock->SetNow(base::Time::FromTimeT(2));
454 std::string encoded;
455 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
456 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
457 ChromeUserMetricsExtension parsed;
458 ASSERT_TRUE(parsed.ParseFromString(encoded));
459 EXPECT_TRUE(parsed.has_time_log_created());
460 EXPECT_EQ(parsed.time_log_created().time_sec(), 1);
461 EXPECT_EQ(parsed.time_log_created().time_source(),
462 ChromeUserMetricsExtension::RealLocalTime::CLIENT_CLOCK);
463 // The timezone should not be set in the time_log_created field.
464 EXPECT_FALSE(parsed.time_log_created().has_time_zone_offset_from_gmt_sec());
465 EXPECT_TRUE(parsed.has_time_log_closed());
466 EXPECT_EQ(parsed.time_log_closed().time_sec(), 2);
467 EXPECT_EQ(parsed.time_log_closed().time_source(),
468 ChromeUserMetricsExtension::RealLocalTime::CLIENT_CLOCK);
469 // The timezone should be set, but we don't check what it is.
470 EXPECT_TRUE(parsed.time_log_closed().has_time_zone_offset_from_gmt_sec());
471 }
472
TEST_F(MetricsLogTest,Timestamps_OngoingLogLog_WithNetworkClockExists_AlwaysUnavailable)473 TEST_F(MetricsLogTest,
474 Timestamps_OngoingLogLog_WithNetworkClockExists_AlwaysUnavailable) {
475 // Setup a network clock that doesn't provide a timestamp (time unavailable).
476 base::test::TaskEnvironment task_environment(
477 base::test::TaskEnvironment::MainThreadType::IO);
478 std::unique_ptr<network_time::FieldTrialTest> field_trial_test(
479 new network_time::FieldTrialTest());
480 field_trial_test->SetFeatureParams(
481 true, 0.0, network_time::NetworkTimeTracker::FETCHES_ON_DEMAND_ONLY);
482 scoped_refptr<network::TestSharedURLLoaderFactory> shared_url_loader_factory =
483 base::MakeRefCounted<network::TestSharedURLLoaderFactory>();
484 TestingPrefServiceSimple pref_service;
485 network_time::NetworkTimeTracker::RegisterPrefs(pref_service.registry());
486 network_time::NetworkTimeTracker network_time_tracker(
487 std::make_unique<base::DefaultClock>(),
488 std::make_unique<base::DefaultTickClock>(), &pref_service,
489 shared_url_loader_factory, /*fetch_behavior=*/std::nullopt);
490
491 // Set up the backup client clock.
492 TestMetricsServiceClient client;
493 std::unique_ptr<base::SimpleTestClock> clock =
494 std::make_unique<base::SimpleTestClock>();
495
496 // Should have times from regular (ongoing) logs. These times should come
497 // from the backup client clock, not the (unavailable) network clock.
498 clock->SetNow(base::Time::FromTimeT(1));
499 MetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, clock.get(),
500 &network_time_tracker, &client);
501 clock->SetNow(base::Time::FromTimeT(2));
502
503 // Check the output.
504 std::string encoded;
505 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
506 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
507 ChromeUserMetricsExtension parsed;
508 ASSERT_TRUE(parsed.ParseFromString(encoded));
509 EXPECT_TRUE(parsed.has_time_log_created());
510 EXPECT_EQ(parsed.time_log_created().time_sec(), 1);
511 EXPECT_EQ(parsed.time_log_created().time_source(),
512 ChromeUserMetricsExtension::RealLocalTime::CLIENT_CLOCK);
513 // The timezone should not be set in the time_log_created field.
514 EXPECT_FALSE(parsed.time_log_created().has_time_zone_offset_from_gmt_sec());
515 EXPECT_TRUE(parsed.has_time_log_closed());
516 EXPECT_EQ(parsed.time_log_closed().time_sec(), 2);
517 EXPECT_EQ(parsed.time_log_closed().time_source(),
518 ChromeUserMetricsExtension::RealLocalTime::CLIENT_CLOCK);
519 // The timezone should be set, but we don't check what it is.
520 EXPECT_TRUE(parsed.time_log_closed().has_time_zone_offset_from_gmt_sec());
521 }
522
TEST_F(MetricsLogTest,Timestamps_OngoingLogLog_WithNetworkClockExists_UnavailableThenAvailable)523 TEST_F(
524 MetricsLogTest,
525 Timestamps_OngoingLogLog_WithNetworkClockExists_UnavailableThenAvailable) {
526 // Setup a network clock that initially doesn't provide a timestamp (time
527 // unavailable).
528 base::test::TaskEnvironment task_environment(
529 base::test::TaskEnvironment::MainThreadType::IO);
530 std::unique_ptr<network_time::FieldTrialTest> field_trial_test(
531 new network_time::FieldTrialTest());
532 field_trial_test->SetFeatureParams(
533 true, 0.0, network_time::NetworkTimeTracker::FETCHES_ON_DEMAND_ONLY);
534 scoped_refptr<network::TestSharedURLLoaderFactory> shared_url_loader_factory =
535 base::MakeRefCounted<network::TestSharedURLLoaderFactory>();
536 TestingPrefServiceSimple pref_service;
537 network_time::NetworkTimeTracker::RegisterPrefs(pref_service.registry());
538 base::SimpleTestClock* clock = new base::SimpleTestClock;
539 base::SimpleTestTickClock* tick_clock = new base::SimpleTestTickClock();
540 // Do this to be sure that |is_null| returns false.
541 clock->Advance(base::Days(111));
542 tick_clock->Advance(base::Days(222));
543 network_time::NetworkTimeTracker network_time_tracker(
544 std::unique_ptr<base::Clock>(clock),
545 std::unique_ptr<const base::TickClock>(tick_clock), &pref_service,
546 shared_url_loader_factory, /*fetch_behavior=*/std::nullopt);
547
548 // Should have times from regular (ongoing) logs. The creation time should
549 // come from the backup client clock; the closure time should come from the
550 // network clock.
551 clock->SetNow(base::Time::FromTimeT(1));
552 TestMetricsServiceClient client;
553 MetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, clock,
554 &network_time_tracker, &client);
555 // Advance the backup client clock. (Value should not be used; merely
556 // advanced to make sure the new value doesn't show up anywhere.)
557 clock->SetNow(base::Time::FromTimeT(2));
558 // Set the network time tracker.
559 UpdateNetworkTime(&network_time_tracker, tick_clock,
560 base::Time::FromTimeT(3));
561
562 // Check the output.
563 std::string encoded;
564 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
565 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
566 ChromeUserMetricsExtension parsed;
567 ASSERT_TRUE(parsed.ParseFromString(encoded));
568 EXPECT_TRUE(parsed.has_time_log_created());
569 EXPECT_EQ(parsed.time_log_created().time_sec(), 1);
570 EXPECT_EQ(parsed.time_log_created().time_source(),
571 ChromeUserMetricsExtension::RealLocalTime::CLIENT_CLOCK);
572 // The timezone should not be set in the time_log_created field.
573 EXPECT_FALSE(parsed.time_log_created().has_time_zone_offset_from_gmt_sec());
574 EXPECT_TRUE(parsed.has_time_log_closed());
575 EXPECT_EQ(parsed.time_log_closed().time_sec(), 3);
576 EXPECT_EQ(parsed.time_log_closed().time_source(),
577 ChromeUserMetricsExtension::RealLocalTime::NETWORK_TIME_CLOCK);
578 // The timezone should be set, but we don't check what it is.
579 EXPECT_TRUE(parsed.time_log_closed().has_time_zone_offset_from_gmt_sec());
580 }
581
TEST_F(MetricsLogTest,Timestamps_OngoingLogLog_WithNetworkClockExists_AlwaysAvailable)582 TEST_F(MetricsLogTest,
583 Timestamps_OngoingLogLog_WithNetworkClockExists_AlwaysAvailable) {
584 // Setup a network clock that provides a timestamp.
585 base::test::TaskEnvironment task_environment(
586 base::test::TaskEnvironment::MainThreadType::IO);
587 std::unique_ptr<network_time::FieldTrialTest> field_trial_test(
588 new network_time::FieldTrialTest());
589 field_trial_test->SetFeatureParams(
590 true, 0.0, network_time::NetworkTimeTracker::FETCHES_ON_DEMAND_ONLY);
591 scoped_refptr<network::TestSharedURLLoaderFactory> shared_url_loader_factory =
592 base::MakeRefCounted<network::TestSharedURLLoaderFactory>();
593 TestingPrefServiceSimple pref_service;
594 network_time::NetworkTimeTracker::RegisterPrefs(pref_service.registry());
595 base::SimpleTestClock* clock = new base::SimpleTestClock;
596 base::SimpleTestTickClock* tick_clock = new base::SimpleTestTickClock();
597 // Do this to be sure that |is_null| returns false.
598 clock->Advance(base::Days(111));
599 tick_clock->Advance(base::Days(222));
600 network_time::NetworkTimeTracker network_time_tracker(
601 std::unique_ptr<base::Clock>(clock),
602 std::unique_ptr<const base::TickClock>(tick_clock), &pref_service,
603 shared_url_loader_factory, /*fetch_behavior=*/std::nullopt);
604
605 // Should have times from regular (ongoing) logs. These times should come
606 // from the network clock.
607 // Set the backup client clock time. (Value should not be used; merely set
608 // to make sure the value doesn't show up anywhere.)
609 clock->SetNow(base::Time::FromTimeT(1));
610 // Set the network time tracker.
611 UpdateNetworkTime(&network_time_tracker, tick_clock,
612 base::Time::FromTimeT(2));
613 TestMetricsServiceClient client;
614 MetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, clock,
615 &network_time_tracker, &client);
616 // Advance the backup client clock. (Value should not be used; merely
617 // advanced to make sure the new value doesn't show up anywhere.)
618 clock->SetNow(base::Time::FromTimeT(3));
619 // Advance and set the network time clock.
620 UpdateNetworkTime(&network_time_tracker, tick_clock,
621 base::Time::FromTimeT(4));
622
623 // Check the output.
624 std::string encoded;
625 log.FinalizeLog(/*truncate_events=*/false, client_.GetVersionString(),
626 log.GetCurrentClockTime(/*record_time_zone=*/true), &encoded);
627 ChromeUserMetricsExtension parsed;
628 ASSERT_TRUE(parsed.ParseFromString(encoded));
629 EXPECT_TRUE(parsed.has_time_log_created());
630 // Time should be the first time returned by the network time tracker.
631 EXPECT_EQ(parsed.time_log_created().time_sec(), 2);
632 EXPECT_EQ(parsed.time_log_created().time_source(),
633 ChromeUserMetricsExtension::RealLocalTime::NETWORK_TIME_CLOCK);
634 // The timezone should not be set in the time_log_created field.
635 EXPECT_FALSE(parsed.time_log_created().has_time_zone_offset_from_gmt_sec());
636 EXPECT_TRUE(parsed.has_time_log_closed());
637 // Time should be the second time returned by the network time tracker.
638 EXPECT_EQ(parsed.time_log_closed().time_sec(), 4);
639 EXPECT_EQ(parsed.time_log_closed().time_source(),
640 ChromeUserMetricsExtension::RealLocalTime::NETWORK_TIME_CLOCK);
641 // The timezone should be set, but we don't check what it is.
642 EXPECT_TRUE(parsed.time_log_closed().has_time_zone_offset_from_gmt_sec());
643 }
644
TEST_F(MetricsLogTest,HistogramBucketFields)645 TEST_F(MetricsLogTest, HistogramBucketFields) {
646 // Create buckets: 1-5, 5-7, 7-8, 8-9, 9-10, 10-11, 11-12.
647 base::BucketRanges ranges(8);
648 ranges.set_range(0, 1);
649 ranges.set_range(1, 5);
650 ranges.set_range(2, 7);
651 ranges.set_range(3, 8);
652 ranges.set_range(4, 9);
653 ranges.set_range(5, 10);
654 ranges.set_range(6, 11);
655 ranges.set_range(7, 12);
656
657 base::SampleVector samples(1, &ranges);
658 samples.Accumulate(3, 1); // Bucket 1-5.
659 samples.Accumulate(6, 1); // Bucket 5-7.
660 samples.Accumulate(8, 1); // Bucket 8-9. (7-8 skipped)
661 samples.Accumulate(10, 1); // Bucket 10-11. (9-10 skipped)
662 samples.Accumulate(11, 1); // Bucket 11-12.
663 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
664 log.RecordHistogramDelta("Test", samples);
665
666 const ChromeUserMetricsExtension& uma_proto = log.uma_proto();
667 const HistogramEventProto& histogram_proto =
668 uma_proto.histogram_event(uma_proto.histogram_event_size() - 1);
669
670 // Buckets with samples: 1-5, 5-7, 8-9, 10-11, 11-12.
671 // Should become: 1-/, 5-7, /-9, 10-/, /-12.
672 ASSERT_EQ(5, histogram_proto.bucket_size());
673
674 // 1-5 becomes 1-/ (max is same as next min).
675 EXPECT_TRUE(histogram_proto.bucket(0).has_min());
676 EXPECT_FALSE(histogram_proto.bucket(0).has_max());
677 EXPECT_EQ(1, histogram_proto.bucket(0).min());
678
679 // 5-7 stays 5-7 (no optimization possible).
680 EXPECT_TRUE(histogram_proto.bucket(1).has_min());
681 EXPECT_TRUE(histogram_proto.bucket(1).has_max());
682 EXPECT_EQ(5, histogram_proto.bucket(1).min());
683 EXPECT_EQ(7, histogram_proto.bucket(1).max());
684
685 // 8-9 becomes /-9 (min is same as max - 1).
686 EXPECT_FALSE(histogram_proto.bucket(2).has_min());
687 EXPECT_TRUE(histogram_proto.bucket(2).has_max());
688 EXPECT_EQ(9, histogram_proto.bucket(2).max());
689
690 // 10-11 becomes 10-/ (both optimizations apply, omit max is prioritized).
691 EXPECT_TRUE(histogram_proto.bucket(3).has_min());
692 EXPECT_FALSE(histogram_proto.bucket(3).has_max());
693 EXPECT_EQ(10, histogram_proto.bucket(3).min());
694
695 // 11-12 becomes /-12 (last record must keep max, min is same as max - 1).
696 EXPECT_FALSE(histogram_proto.bucket(4).has_min());
697 EXPECT_TRUE(histogram_proto.bucket(4).has_max());
698 EXPECT_EQ(12, histogram_proto.bucket(4).max());
699 }
700
TEST_F(MetricsLogTest,HistogramSamplesCount)701 TEST_F(MetricsLogTest, HistogramSamplesCount) {
702 const std::string histogram_name = "test";
703 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
704
705 // Create buckets: 1-5.
706 base::BucketRanges ranges(2);
707 ranges.set_range(0, 1);
708 ranges.set_range(1, 5);
709
710 // Add two samples.
711 base::SampleVector samples(1, &ranges);
712 samples.Accumulate(3, 2);
713 log.RecordHistogramDelta(histogram_name, samples);
714
715 EXPECT_EQ(2, log.log_metadata().samples_count.value());
716
717 // Add two more samples.
718 log.RecordHistogramDelta(histogram_name, samples);
719 EXPECT_EQ(4, log.log_metadata().samples_count.value());
720 }
721
TEST_F(MetricsLogTest,RecordEnvironment)722 TEST_F(MetricsLogTest, RecordEnvironment) {
723 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
724
725 DelegatingProvider delegating_provider;
726 auto cpu_provider = std::make_unique<metrics::CPUMetricsProvider>();
727 delegating_provider.RegisterMetricsProvider(std::move(cpu_provider));
728 log.RecordEnvironment(&delegating_provider);
729
730 // Check non-system profile values.
731 EXPECT_EQ(MetricsLog::Hash(kClientId), log.uma_proto().client_id());
732 EXPECT_EQ(kSessionId, log.uma_proto().session_id());
733 // Check that the system profile on the log has the correct values set.
734 CheckSystemProfile(log.system_profile());
735
736 // Call RecordEnvironment() again and verify things are are still filled in.
737 log.RecordEnvironment(&delegating_provider);
738
739 // Check non-system profile values.
740 EXPECT_EQ(MetricsLog::Hash(kClientId), log.uma_proto().client_id());
741 EXPECT_EQ(kSessionId, log.uma_proto().session_id());
742 // Check that the system profile on the log has the correct values set.
743 CheckSystemProfile(log.system_profile());
744 }
745
TEST_F(MetricsLogTest,RecordEnvironmentExtendedStable)746 TEST_F(MetricsLogTest, RecordEnvironmentExtendedStable) {
747 client_.set_is_extended_stable_channel(true);
748 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
749
750 DelegatingProvider delegating_provider;
751 auto cpu_provider = std::make_unique<metrics::CPUMetricsProvider>();
752 delegating_provider.RegisterMetricsProvider(std::move(cpu_provider));
753 log.RecordEnvironment(&delegating_provider);
754
755 EXPECT_TRUE(log.system_profile().has_is_extended_stable_channel());
756 EXPECT_TRUE(log.system_profile().is_extended_stable_channel());
757 }
758
TEST_F(MetricsLogTest,RecordEnvironmentEnableDefault)759 TEST_F(MetricsLogTest, RecordEnvironmentEnableDefault) {
760 TestMetricsLog log_unknown(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
761 &client_);
762
763 DelegatingProvider delegating_provider;
764 log_unknown.RecordEnvironment(&delegating_provider);
765 EXPECT_FALSE(log_unknown.system_profile().has_uma_default_state());
766
767 client_.set_enable_default(EnableMetricsDefault::OPT_IN);
768 TestMetricsLog log_opt_in(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
769 &client_);
770 log_opt_in.RecordEnvironment(&delegating_provider);
771 EXPECT_TRUE(log_opt_in.system_profile().has_uma_default_state());
772 EXPECT_EQ(SystemProfileProto_UmaDefaultState_OPT_IN,
773 log_opt_in.system_profile().uma_default_state());
774
775 client_.set_enable_default(EnableMetricsDefault::OPT_OUT);
776 TestMetricsLog log_opt_out(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
777 &client_);
778 log_opt_out.RecordEnvironment(&delegating_provider);
779 EXPECT_TRUE(log_opt_out.system_profile().has_uma_default_state());
780 EXPECT_EQ(SystemProfileProto_UmaDefaultState_OPT_OUT,
781 log_opt_out.system_profile().uma_default_state());
782
783 client_.set_reporting_is_managed(true);
784 TestMetricsLog log_managed(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
785 &client_);
786 log_managed.RecordEnvironment(&delegating_provider);
787 EXPECT_TRUE(log_managed.system_profile().has_uma_default_state());
788 EXPECT_EQ(SystemProfileProto_UmaDefaultState_POLICY_FORCED_ENABLED,
789 log_managed.system_profile().uma_default_state());
790 }
791
TEST_F(MetricsLogTest,InitialLogStabilityMetrics)792 TEST_F(MetricsLogTest, InitialLogStabilityMetrics) {
793 TestMetricsLog log(kClientId, kSessionId, MetricsLog::INITIAL_STABILITY_LOG,
794 &client_);
795 TestMetricsProvider* test_provider = new TestMetricsProvider();
796 DelegatingProvider delegating_provider;
797 delegating_provider.RegisterMetricsProvider(
798 base::WrapUnique<MetricsProvider>(test_provider));
799 log.RecordEnvironment(&delegating_provider);
800 log.RecordPreviousSessionData(&delegating_provider, &prefs_);
801
802 // The test provider should have been called upon to provide initial
803 // stability and regular stability metrics.
804 EXPECT_TRUE(test_provider->provide_initial_stability_metrics_called());
805 EXPECT_TRUE(test_provider->provide_stability_metrics_called());
806 }
807
TEST_F(MetricsLogTest,OngoingLogStabilityMetrics)808 TEST_F(MetricsLogTest, OngoingLogStabilityMetrics) {
809 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
810 TestMetricsProvider* test_provider = new TestMetricsProvider();
811 DelegatingProvider delegating_provider;
812 delegating_provider.RegisterMetricsProvider(
813 base::WrapUnique<MetricsProvider>(test_provider));
814 log.RecordEnvironment(&delegating_provider);
815 log.RecordCurrentSessionData(base::TimeDelta(), base::TimeDelta(),
816 &delegating_provider, &prefs_);
817
818 // The test provider should have been called upon to provide regular but not
819 // initial stability metrics.
820 EXPECT_FALSE(test_provider->provide_initial_stability_metrics_called());
821 EXPECT_TRUE(test_provider->provide_stability_metrics_called());
822 }
823
TEST_F(MetricsLogTest,ChromeChannelWrittenToProtobuf)824 TEST_F(MetricsLogTest, ChromeChannelWrittenToProtobuf) {
825 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
826 EXPECT_TRUE(log.uma_proto().system_profile().has_channel());
827 }
828
TEST_F(MetricsLogTest,ProductNotSetIfDefault)829 TEST_F(MetricsLogTest, ProductNotSetIfDefault) {
830 EXPECT_EQ(ChromeUserMetricsExtension::CHROME, client_.GetProduct());
831 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
832 // Check that the product isn't set, since it's default and also verify the
833 // default value is indeed equal to Chrome.
834 EXPECT_FALSE(log.uma_proto().has_product());
835 EXPECT_EQ(ChromeUserMetricsExtension::CHROME, log.uma_proto().product());
836 }
837
TEST_F(MetricsLogTest,ProductSetIfNotDefault)838 TEST_F(MetricsLogTest, ProductSetIfNotDefault) {
839 const int32_t kTestProduct = 100;
840 EXPECT_NE(ChromeUserMetricsExtension::CHROME, kTestProduct);
841 client_.set_product(kTestProduct);
842 TestMetricsLog log(kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client_);
843 // Check that the product is set to |kTestProduct|.
844 EXPECT_TRUE(log.uma_proto().has_product());
845 EXPECT_EQ(kTestProduct, log.uma_proto().product());
846 }
847
TEST_F(MetricsLogTest,ToInstallerPackage)848 TEST_F(MetricsLogTest, ToInstallerPackage) {
849 using internal::ToInstallerPackage;
850 EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_NONE, ToInstallerPackage(""));
851 EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_GOOGLE_PLAY_STORE,
852 ToInstallerPackage("com.android.vending"));
853 EXPECT_EQ(SystemProfileProto::INSTALLER_PACKAGE_OTHER,
854 ToInstallerPackage("foo"));
855 }
856
857 } // namespace metrics
858