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 //------------------------------------------------------------------------------
6 // Description of a MetricsService instance's life cycle.
7 //
8 // OVERVIEW
9 //
10 // A MetricsService instance is typically created at application startup. It is
11 // the central controller for the acquisition of log data, and the automatic
12 // transmission of that log data to an external server. Its major job is to
13 // manage logs, grouping them for transmission, and transmitting them. As part
14 // of its grouping, MS finalizes logs by including some just-in-time gathered
15 // memory statistics, snapshotting the current stats of numerous histograms,
16 // closing the logs, translating to protocol buffer format, and compressing the
17 // results for transmission. Transmission includes submitting a compressed log
18 // as data in a URL-post, and retransmitting (or retaining at process
19 // termination) if the attempted transmission failed. Retention across process
20 // terminations is done using the PrefServices facilities. The retained logs
21 // (the ones that never got transmitted) are compressed and base64-encoded
22 // before being persisted.
23 //
24 // Logs fall into one of two categories: "initial logs," and "ongoing logs."
25 // There is at most one initial log sent for each complete run of Chrome (from
26 // startup, to browser shutdown). An initial log is generally transmitted some
27 // short time (1 minute?) after startup, and includes stats such as recent crash
28 // info, the number and types of plugins, etc. The external server's response
29 // to the initial log conceptually tells this MS if it should continue
30 // transmitting logs (during this session). The server response can actually be
31 // much more detailed, and always includes (at a minimum) how often additional
32 // ongoing logs should be sent.
33 //
34 // After the above initial log, a series of ongoing logs will be transmitted.
35 // The first ongoing log actually begins to accumulate information stating when
36 // the MS was first constructed. Note that even though the initial log is
37 // commonly sent a full minute after startup, the initial log does not include
38 // much in the way of user stats. The most common interlog period (delay)
39 // is 30 minutes. That time period starts when the first user action causes a
40 // logging event. This means that if there is no user action, there may be long
41 // periods without any (ongoing) log transmissions. Ongoing logs typically
42 // contain very detailed records of user activities (ex: opened tab, closed
43 // tab, fetched URL, maximized window, etc.) In addition, just before an
44 // ongoing log is closed out, a call is made to gather memory statistics. Those
45 // memory statistics are deposited into a histogram, and the log finalization
46 // code is then called. In the finalization, a call to a Histogram server
47 // acquires a list of all local histograms that have been flagged for upload
48 // to the UMA server. The finalization also acquires the most recent number
49 // of page loads, along with any counts of renderer or plugin crashes.
50 //
51 // When the browser shuts down, there will typically be a fragment of an ongoing
52 // log that has not yet been transmitted. At shutdown time, that fragment is
53 // closed (including snapshotting histograms), and persisted, for potential
54 // transmission during a future run of the product.
55 //
56 // There are two slightly abnormal shutdown conditions. There is a
57 // "disconnected scenario," and a "really fast startup and shutdown" scenario.
58 // In the "never connected" situation, the user has (during the running of the
59 // process) never established an internet connection. As a result, attempts to
60 // transmit the initial log have failed, and a lot(?) of data has accumulated in
61 // the ongoing log (which didn't yet get closed, because there was never even a
62 // contemplation of sending it). There is also a kindred "lost connection"
63 // situation, where a loss of connection prevented an ongoing log from being
64 // transmitted, and a (still open) log was stuck accumulating a lot(?) of data,
65 // while the earlier log retried its transmission. In both of these
66 // disconnected situations, two logs need to be, and are, persistently stored
67 // for future transmission.
68 //
69 // The other unusual shutdown condition, termed "really fast startup and
70 // shutdown," involves the deliberate user termination of the process before
71 // the initial log is even formed or transmitted. In that situation, no logging
72 // is done, but the historical crash statistics remain (unlogged) for inclusion
73 // in a future run's initial log. (i.e., we don't lose crash stats).
74 //
75 // With the above overview, we can now describe the state machine's various
76 // states, based on the State enum specified in the state_ member. Those states
77 // are:
78 //
79 // CONSTRUCTED, // Constructor was called.
80 // INITIALIZED, // InitializeMetricsRecordingState() was called.
81 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
82 // INIT_TASK_DONE, // Waiting for timer to send the first ongoing log.
83 // SENDING_LOGS, // Sending logs and creating new ones when we run out.
84 //
85 // In more detail, we have:
86 //
87 // INIT_TASK_SCHEDULED, // Waiting for deferred init tasks to finish.
88 // Typically about 30 seconds after startup, a task is sent to a background
89 // thread to perform deferred (lower priority and slower) initialization steps
90 // such as getting the list of plugins. That task will (when complete) make an
91 // async callback (via a Task) to indicate the completion.
92 //
93 // INIT_TASK_DONE, // Waiting for timer to send first ongoing log.
94 // The callback has arrived, and it is now possible for an ongoing log to be
95 // created. This callback typically arrives back less than one second after
96 // the deferred init task is dispatched.
97 //
98 // SENDING_LOGS, // Sending logs and creating new ones when we run out.
99 // Logs from previous sessions have been loaded, and an optional initial
100 // stability log has been created. We will send all of these logs, and when
101 // they run out, we will start cutting new logs to send. We will also cut a new
102 // log if we expect a shutdown.
103 //
104 // The progression through the above states is simple, and sequential.
105 // States proceed from INITIALIZED to SENDING_LOGS, and remain in the latter
106 // until shutdown.
107 //
108 // Also note that whenever we successfully send a log, we mirror the list
109 // of logs into the PrefService. This ensures that IF we crash, we won't start
110 // up and retransmit our old logs again.
111 //
112 // Due to race conditions, it is always possible that a log file could be sent
113 // twice. For example, if a log file is sent, but not yet acknowledged by
114 // the external server, and the user shuts down, then a copy of the log may be
115 // saved for re-transmission. These duplicates could be filtered out server
116 // side, but are not expected to be a significant problem.
117 //
118 //
119 //------------------------------------------------------------------------------
120
121 #include "components/metrics/metrics_service.h"
122
123 #include <stddef.h>
124
125 #include <algorithm>
126 #include <memory>
127 #include <utility>
128
129 #include "base/callback_list.h"
130 #include "base/functional/bind.h"
131 #include "base/functional/callback.h"
132 #include "base/location.h"
133 #include "base/metrics/histogram_base.h"
134 #include "base/metrics/histogram_flattener.h"
135 #include "base/metrics/histogram_functions.h"
136 #include "base/metrics/histogram_macros.h"
137 #include "base/metrics/histogram_macros_local.h"
138 #include "base/metrics/histogram_samples.h"
139 #include "base/metrics/persistent_histogram_allocator.h"
140 #include "base/metrics/statistics_recorder.h"
141 #include "base/process/process_handle.h"
142 #include "base/rand_util.h"
143 #include "base/strings/string_piece.h"
144 #include "base/task/sequenced_task_runner.h"
145 #include "base/task/single_thread_task_runner.h"
146 #include "base/task/task_traits.h"
147 #include "base/task/thread_pool.h"
148 #include "base/time/time.h"
149 #include "build/build_config.h"
150 #include "build/chromeos_buildflags.h"
151 #include "components/metrics/clean_exit_beacon.h"
152 #include "components/metrics/environment_recorder.h"
153 #include "components/metrics/field_trials_provider.h"
154 #include "components/metrics/metrics_features.h"
155 #include "components/metrics/metrics_log.h"
156 #include "components/metrics/metrics_log_uploader.h"
157 #include "components/metrics/metrics_logs_event_manager.h"
158 #include "components/metrics/metrics_pref_names.h"
159 #include "components/metrics/metrics_rotation_scheduler.h"
160 #include "components/metrics/metrics_service_client.h"
161 #include "components/metrics/metrics_service_observer.h"
162 #include "components/metrics/metrics_state_manager.h"
163 #include "components/metrics/metrics_switches.h"
164 #include "components/metrics/persistent_system_profile.h"
165 #include "components/metrics/stability_metrics_provider.h"
166 #include "components/metrics/url_constants.h"
167 #include "components/prefs/pref_registry_simple.h"
168 #include "components/prefs/pref_service.h"
169 #include "components/variations/entropy_provider.h"
170
171 #if !BUILDFLAG(IS_ANDROID)
172 #include "components/keep_alive_registry/keep_alive_registry.h"
173 #include "components/keep_alive_registry/keep_alive_types.h"
174 #include "components/keep_alive_registry/scoped_keep_alive.h"
175 #endif // !BUILDFLAG(IS_ANDROID)
176
177 namespace metrics {
178 namespace {
179
180 // Used to write histogram data to a log. Does not take ownership of the log.
181 class IndependentFlattener : public base::HistogramFlattener {
182 public:
IndependentFlattener(MetricsLog * log)183 explicit IndependentFlattener(MetricsLog* log) : log_(log) {}
184
185 IndependentFlattener(const IndependentFlattener&) = delete;
186 IndependentFlattener& operator=(const IndependentFlattener&) = delete;
187
188 ~IndependentFlattener() override = default;
189
190 // base::HistogramFlattener:
RecordDelta(const base::HistogramBase & histogram,const base::HistogramSamples & snapshot)191 void RecordDelta(const base::HistogramBase& histogram,
192 const base::HistogramSamples& snapshot) override {
193 CHECK(histogram.HasFlags(base::HistogramBase::kUmaTargetedHistogramFlag));
194 log_->RecordHistogramDelta(histogram.histogram_name(), snapshot);
195 }
196
197 private:
198 const raw_ptr<MetricsLog, AcrossTasksDanglingUntriaged> log_;
199 };
200
201 // Used to mark histogram samples as reported so that they are not included in
202 // the next log. A histogram's snapshot samples are simply discarded/ignored
203 // when attempting to record them through this |HistogramFlattener|.
204 class DiscardingFlattener : public base::HistogramFlattener {
205 public:
206 DiscardingFlattener() = default;
207
208 DiscardingFlattener(const DiscardingFlattener&) = delete;
209 DiscardingFlattener& operator=(const DiscardingFlattener&) = delete;
210
211 ~DiscardingFlattener() override = default;
212
RecordDelta(const base::HistogramBase & histogram,const base::HistogramSamples & snapshot)213 void RecordDelta(const base::HistogramBase& histogram,
214 const base::HistogramSamples& snapshot) override {
215 // No-op. We discard the samples.
216 }
217 };
218
219 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
220 // Emits a histogram upon instantiation, and on destruction. Used to measure how
221 // often the browser is ungracefully killed between two different points. In
222 // particular, currently, this is used on mobile to measure how often the
223 // browser is killed while finalizing a log, right after backgrounding. This
224 // scenario is prone to data loss because a histogram may have been snapshotted
225 // and put into a log, but the browser was killed before it could be fully
226 // finalized and stored.
227 //
228 // TODO(crbug/1293026): Consider improving this. In particular, the "Started"
229 // bucket is emitted before finalizing the log, and the "Finished" bucket is
230 // emitted after. Hence, the latter will be reported in a different log, which
231 // may cause a "lag" and/or bias (e.g. if the latter log is more prone to loss).
232 // A better way to do this is to allocate an object on the persistent memory
233 // upon instantiation, and flip a bit in it upon destruction. A future session
234 // that will consume this persistent memory should take care of emitting the
235 // histogram samples.
236 class ScopedTerminationChecker {
237 public:
238 // These values are persisted to logs. Entries should not be renumbered and
239 // numeric values should never be reused.
240 enum class Status {
241 kStarted = 0,
242 kFinished = 1,
243 kMaxValue = kFinished,
244 };
245
ScopedTerminationChecker(base::StringPiece histogram_name)246 explicit ScopedTerminationChecker(base::StringPiece histogram_name) {
247 // Do nothing if the persistent histogram system is not being used.
248 // Otherwise, the "Finished" bucket may be more prone to loss, which may
249 // incorrectly make it seem like the browser was killed in between the
250 // scoped code.
251 if (!base::GlobalHistogramAllocator::Get()) {
252 return;
253 }
254
255 active_ = true;
256 histogram_name_ = histogram_name;
257 base::UmaHistogramEnumeration(histogram_name_, Status::kStarted);
258 }
259
260 ScopedTerminationChecker(const ScopedTerminationChecker& other) = delete;
261 ScopedTerminationChecker& operator=(const ScopedTerminationChecker& other) =
262 delete;
263
~ScopedTerminationChecker()264 ~ScopedTerminationChecker() {
265 if (!active_) {
266 return;
267 }
268 base::UmaHistogramEnumeration(histogram_name_, Status::kFinished);
269 }
270
271 private:
272 // Name of the histogram to emit to upon instantiation/destruction.
273 std::string histogram_name_;
274
275 // Whether or not this will emit histograms. In particular, if this browser
276 // session does not make use of persistent memory, this will be false, and
277 // this object will do nothing.
278 bool active_ = false;
279 };
280 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
281
282 // The delay, in seconds, after starting recording before doing expensive
283 // initialization work.
284 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
285 // On mobile devices, a significant portion of sessions last less than a minute.
286 // Use a shorter timer on these platforms to avoid losing data.
287 // TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
288 // that it occurs after the user gets their initial page.
289 const int kInitializationDelaySeconds = 5;
290 #else
291 const int kInitializationDelaySeconds = 30;
292 #endif
293
294 // The browser last live timestamp is updated every 15 minutes.
295 const int kUpdateAliveTimestampSeconds = 15 * 60;
296
297 #if BUILDFLAG(IS_CHROMEOS_ASH)
298 enum UserLogStoreState {
299 kSetPostSendLogsState = 0,
300 kSetPreSendLogsState = 1,
301 kUnsetPostSendLogsState = 2,
302 kUnsetPreSendLogsState = 3,
303 kMaxValue = kUnsetPreSendLogsState,
304 };
305
RecordUserLogStoreState(UserLogStoreState state)306 void RecordUserLogStoreState(UserLogStoreState state) {
307 base::UmaHistogramEnumeration("UMA.CrosPerUser.UserLogStoreState", state);
308 }
309 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
310
311 } // namespace
312
313 // static
RegisterPrefs(PrefRegistrySimple * registry)314 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
315 CleanExitBeacon::RegisterPrefs(registry);
316 MetricsStateManager::RegisterPrefs(registry);
317 MetricsLog::RegisterPrefs(registry);
318 StabilityMetricsProvider::RegisterPrefs(registry);
319 MetricsReportingService::RegisterPrefs(registry);
320
321 registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
322 }
323
MetricsService(MetricsStateManager * state_manager,MetricsServiceClient * client,PrefService * local_state)324 MetricsService::MetricsService(MetricsStateManager* state_manager,
325 MetricsServiceClient* client,
326 PrefService* local_state)
327 : reporting_service_(client, local_state, &logs_event_manager_),
328 state_manager_(state_manager),
329 client_(client),
330 local_state_(local_state),
331 recording_state_(UNSET),
332 test_mode_active_(false),
333 state_(CONSTRUCTED),
334 idle_since_last_transmission_(false),
335 session_id_(-1) {
336 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
337 DCHECK(state_manager_);
338 DCHECK(client_);
339 DCHECK(local_state_);
340
341 // Emit a local histogram, which should not be reported to servers. This is
342 // monitored from the serverside.
343 LOCAL_HISTOGRAM_BOOLEAN("UMA.LocalHistogram", true);
344
345 bool create_logs_event_observer;
346 #ifdef NDEBUG
347 // For non-debug builds, we only create |logs_event_observer_| if the
348 // |kExportUmaLogsToFile| command line flag is passed. This is mostly for
349 // performance reasons: 1) we don't want to have to notify an observer in
350 // non-debug circumstances (there may be heavy work like copying large
351 // strings), and 2) we don't want logs to be lingering in memory.
352 create_logs_event_observer =
353 base::CommandLine::ForCurrentProcess()->HasSwitch(
354 switches::kExportUmaLogsToFile);
355 #else
356 // For debug builds, always create |logs_event_observer_|.
357 create_logs_event_observer = true;
358 #endif // NDEBUG
359
360 if (create_logs_event_observer) {
361 logs_event_observer_ = std::make_unique<MetricsServiceObserver>(
362 MetricsServiceObserver::MetricsServiceType::UMA);
363 logs_event_manager_.AddObserver(logs_event_observer_.get());
364 }
365
366 cloned_install_subscription_ =
367 state_manager->AddOnClonedInstallDetectedCallback(
368 base::BindOnce(&MetricsService::OnClonedInstallDetected,
369 self_ptr_factory_.GetWeakPtr()));
370
371 RegisterMetricsProvider(
372 std::make_unique<StabilityMetricsProvider>(local_state_));
373
374 RegisterMetricsProvider(state_manager_->GetProvider());
375 }
376
~MetricsService()377 MetricsService::~MetricsService() {
378 DisableRecording();
379
380 if (logs_event_observer_) {
381 logs_event_manager_.RemoveObserver(logs_event_observer_.get());
382 const base::CommandLine* command_line =
383 base::CommandLine::ForCurrentProcess();
384 if (command_line->HasSwitch(switches::kExportUmaLogsToFile)) {
385 // We should typically not write to files on the main thread, but since
386 // this only happens when |kExportUmaLogsToFile| is passed (which
387 // indicates debugging), this should be fine.
388 logs_event_observer_->ExportLogsToFile(
389 command_line->GetSwitchValuePath(switches::kExportUmaLogsToFile));
390 }
391 }
392
393 // Emit a local histogram, which should not be reported to servers. This is
394 // monitored from the serverside. Because this is emitted after closing the
395 // last log before shutdown, this sample should be retrieved by the persistent
396 // histograms system in a follow up session. This is to ensure independent
397 // logs do not include local histograms, a previously buggy behaviour.
398 LOCAL_HISTOGRAM_BOOLEAN("UMA.LocalHistogram", true);
399 }
400
InitializeMetricsRecordingState()401 void MetricsService::InitializeMetricsRecordingState() {
402 DCHECK_EQ(CONSTRUCTED, state_);
403
404 // The FieldTrialsProvider should be registered last. This ensures that
405 // studies whose features are checked when providers add their information to
406 // the log appear in the active field trials.
407 RegisterMetricsProvider(std::make_unique<variations::FieldTrialsProvider>(
408 client_->GetSyntheticTrialRegistry(), base::StringPiece()));
409
410 reporting_service_.Initialize();
411 InitializeMetricsState();
412
413 base::RepeatingClosure upload_callback = base::BindRepeating(
414 &MetricsService::StartScheduledUpload, self_ptr_factory_.GetWeakPtr());
415
416 rotation_scheduler_ = std::make_unique<MetricsRotationScheduler>(
417 upload_callback,
418 // MetricsServiceClient outlives MetricsService, and
419 // MetricsRotationScheduler is tied to the lifetime of |this|.
420 base::BindRepeating(&MetricsServiceClient::GetUploadInterval,
421 base::Unretained(client_)),
422 client_->ShouldStartUpFastForTesting());
423
424 // Init() has to be called after LogCrash() in order for LogCrash() to work.
425 delegating_provider_.Init();
426
427 state_ = INITIALIZED;
428 }
429
Start()430 void MetricsService::Start() {
431 HandleIdleSinceLastTransmission(false);
432 EnableRecording();
433 EnableReporting();
434 }
435
StartRecordingForTests()436 void MetricsService::StartRecordingForTests() {
437 test_mode_active_ = true;
438 EnableRecording();
439 DisableReporting();
440 }
441
StartUpdatingLastLiveTimestamp()442 void MetricsService::StartUpdatingLastLiveTimestamp() {
443 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
444 FROM_HERE,
445 base::BindOnce(&MetricsService::UpdateLastLiveTimestampTask,
446 self_ptr_factory_.GetWeakPtr()),
447 GetUpdateLastAliveTimestampDelay());
448 }
449
Stop()450 void MetricsService::Stop() {
451 HandleIdleSinceLastTransmission(false);
452 DisableReporting();
453 DisableRecording();
454 }
455
EnableReporting()456 void MetricsService::EnableReporting() {
457 if (reporting_service_.reporting_active())
458 return;
459 reporting_service_.EnableReporting();
460 StartSchedulerIfNecessary();
461 }
462
DisableReporting()463 void MetricsService::DisableReporting() {
464 reporting_service_.DisableReporting();
465 }
466
GetClientId() const467 std::string MetricsService::GetClientId() const {
468 return state_manager_->client_id();
469 }
470
GetLowEntropySource()471 int MetricsService::GetLowEntropySource() {
472 return state_manager_->GetLowEntropySource();
473 }
474
GetOldLowEntropySource()475 int MetricsService::GetOldLowEntropySource() {
476 return state_manager_->GetOldLowEntropySource();
477 }
478
GetPseudoLowEntropySource()479 int MetricsService::GetPseudoLowEntropySource() {
480 return state_manager_->GetPseudoLowEntropySource();
481 }
482
GetLimitedEntropyRandomizationSource()483 std::string_view MetricsService::GetLimitedEntropyRandomizationSource() {
484 return state_manager_->GetLimitedEntropyRandomizationSource();
485 }
486
SetExternalClientId(const std::string & id)487 void MetricsService::SetExternalClientId(const std::string& id) {
488 state_manager_->SetExternalClientId(id);
489 }
490
WasLastShutdownClean() const491 bool MetricsService::WasLastShutdownClean() const {
492 return state_manager_->clean_exit_beacon()->exited_cleanly();
493 }
494
EnableRecording()495 void MetricsService::EnableRecording() {
496 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
497
498 if (recording_state_ == ACTIVE)
499 return;
500 recording_state_ = ACTIVE;
501
502 state_manager_->ForceClientIdCreation();
503 client_->SetMetricsClientId(state_manager_->client_id());
504
505 if (!current_log_) {
506 OpenNewLog();
507 }
508
509 delegating_provider_.OnRecordingEnabled();
510
511 // Fill in the system profile in the log and persist it (to prefs, .pma
512 // and crashpad). This includes running the providers so that information
513 // like field trials and hardware info is provided. If Chrome crashes
514 // before this log is completed, the .pma file will have this system
515 // profile.
516 RecordCurrentEnvironment(current_log_.get(), /*complete=*/false);
517
518 base::RemoveActionCallback(action_callback_);
519 action_callback_ = base::BindRepeating(&MetricsService::OnUserAction,
520 base::Unretained(this));
521 base::AddActionCallback(action_callback_);
522
523 enablement_observers_.Notify(/*enabled=*/true);
524 }
525
DisableRecording()526 void MetricsService::DisableRecording() {
527 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
528
529 if (recording_state_ == INACTIVE)
530 return;
531 recording_state_ = INACTIVE;
532
533 base::RemoveActionCallback(action_callback_);
534
535 delegating_provider_.OnRecordingDisabled();
536
537 base::UmaHistogramBoolean("UMA.MetricsService.PendingOngoingLogOnDisable",
538 pending_ongoing_log_);
539 PushPendingLogsToPersistentStorage(
540 MetricsLogsEventManager::CreateReason::kServiceShutdown);
541
542 // Because histograms may still be emitted after the last log was closed, an
543 // independent log may be created in a future session in order to report
544 // those histograms. To ensure that this independent log contains histograms
545 // that we wish to appear in every log, call OnDidCreateMetricsLog().
546 delegating_provider_.OnDidCreateMetricsLog();
547
548 enablement_observers_.Notify(/*enabled=*/false);
549 }
550
recording_active() const551 bool MetricsService::recording_active() const {
552 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
553 return recording_state_ == ACTIVE;
554 }
555
reporting_active() const556 bool MetricsService::reporting_active() const {
557 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
558 return reporting_service_.reporting_active();
559 }
560
has_unsent_logs() const561 bool MetricsService::has_unsent_logs() const {
562 return reporting_service_.metrics_log_store()->has_unsent_logs();
563 }
564
IsMetricsReportingEnabled() const565 bool MetricsService::IsMetricsReportingEnabled() const {
566 return state_manager_->IsMetricsReportingEnabled();
567 }
568
HandleIdleSinceLastTransmission(bool in_idle)569 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
570 // If there wasn't a lot of action, maybe the computer was asleep, in which
571 // case, the log transmissions should have stopped. Here we start them up
572 // again.
573 if (!in_idle && idle_since_last_transmission_)
574 StartSchedulerIfNecessary();
575 idle_since_last_transmission_ = in_idle;
576 }
577
OnApplicationNotIdle()578 void MetricsService::OnApplicationNotIdle() {
579 if (recording_state_ == ACTIVE)
580 HandleIdleSinceLastTransmission(false);
581 }
582
583 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
OnAppEnterBackground(bool keep_recording_in_background)584 void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
585 is_in_foreground_ = false;
586 reporting_service_.SetIsInForegound(false);
587 if (!keep_recording_in_background) {
588 rotation_scheduler_->Stop();
589 reporting_service_.Stop();
590 }
591
592 state_manager_->LogHasSessionShutdownCleanly(true);
593 // Schedule a write, which happens on a different thread.
594 local_state_->CommitPendingWrite();
595
596 // Give providers a chance to persist histograms as part of being
597 // backgrounded.
598 delegating_provider_.OnAppEnterBackground();
599
600 // At this point, there's no way of knowing when the process will be killed,
601 // so this has to be treated similar to a shutdown, closing and persisting all
602 // logs. Unlike a shutdown, the state is primed to be ready to continue
603 // logging and uploading if the process does return.
604 if (recording_active() && !IsTooEarlyToCloseLog()) {
605 base::UmaHistogramBoolean(
606 "UMA.MetricsService.PendingOngoingLogOnBackgrounded",
607 pending_ongoing_log_);
608 #if BUILDFLAG(IS_ANDROID)
609 client_->MergeSubprocessHistograms();
610 #endif // BUILDFLAG(IS_ANDROID)
611 {
612 ScopedTerminationChecker scoped_termination_checker(
613 "UMA.MetricsService.OnBackgroundedScopedTerminationChecker");
614 PushPendingLogsToPersistentStorage(
615 MetricsLogsEventManager::CreateReason::kBackgrounded);
616 }
617 // Persisting logs closes the current log, so start recording a new log
618 // immediately to capture any background work that might be done before the
619 // process is killed.
620 OpenNewLog();
621 }
622 }
623
OnAppEnterForeground(bool force_open_new_log)624 void MetricsService::OnAppEnterForeground(bool force_open_new_log) {
625 is_in_foreground_ = true;
626 reporting_service_.SetIsInForegound(true);
627 state_manager_->LogHasSessionShutdownCleanly(false);
628 StartSchedulerIfNecessary();
629
630 if (force_open_new_log && recording_active() && !IsTooEarlyToCloseLog()) {
631 base::UmaHistogramBoolean(
632 "UMA.MetricsService.PendingOngoingLogOnForegrounded",
633 pending_ongoing_log_);
634 #if BUILDFLAG(IS_ANDROID)
635 client_->MergeSubprocessHistograms();
636 #endif // BUILDFLAG(IS_ANDROID)
637 // Because state_ >= SENDING_LOGS, PushPendingLogsToPersistentStorage()
638 // will close the log, allowing a new log to be opened.
639 PushPendingLogsToPersistentStorage(
640 MetricsLogsEventManager::CreateReason::kForegrounded);
641 OpenNewLog();
642 }
643 }
644 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
645
OnPageLoadStarted()646 void MetricsService::OnPageLoadStarted() {
647 delegating_provider_.OnPageLoadStarted();
648 }
649
LogCleanShutdown()650 void MetricsService::LogCleanShutdown() {
651 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
652 state_manager_->LogHasSessionShutdownCleanly(true);
653 }
654
ClearSavedStabilityMetrics()655 void MetricsService::ClearSavedStabilityMetrics() {
656 delegating_provider_.ClearSavedStabilityMetrics();
657 // Stability metrics are stored in Local State prefs, so schedule a Local
658 // State write to flush the updated prefs.
659 local_state_->CommitPendingWrite();
660 }
661
MarkCurrentHistogramsAsReported()662 void MetricsService::MarkCurrentHistogramsAsReported() {
663 DiscardingFlattener flattener;
664 base::HistogramSnapshotManager snapshot_manager(&flattener);
665 base::StatisticsRecorder::PrepareDeltas(
666 /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
667 /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
668 &snapshot_manager);
669 }
670
671 #if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserLogStore(std::unique_ptr<UnsentLogStore> user_log_store)672 void MetricsService::SetUserLogStore(
673 std::unique_ptr<UnsentLogStore> user_log_store) {
674 if (log_store()->has_alternate_ongoing_log_store())
675 return;
676
677 if (state_ >= SENDING_LOGS) {
678 // Closes the current log so that a new log can be opened in the user log
679 // store.
680 PushPendingLogsToPersistentStorage(
681 MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreSet);
682 log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
683 OpenNewLog();
684 RecordUserLogStoreState(kSetPostSendLogsState);
685 } else {
686 // Initial log has not yet been created and flushing now would result in
687 // incomplete information in the current log.
688 //
689 // Logs recorded before a user login will be appended to user logs. This
690 // should not happen frequently.
691 //
692 // TODO(crbug.com/40203458): Look for a way to "pause" pre-login logs and
693 // flush when INIT_TASK is done.
694 log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
695 RecordUserLogStoreState(kSetPreSendLogsState);
696 }
697 }
698
UnsetUserLogStore()699 void MetricsService::UnsetUserLogStore() {
700 if (!log_store()->has_alternate_ongoing_log_store())
701 return;
702
703 if (state_ >= SENDING_LOGS) {
704 PushPendingLogsToPersistentStorage(
705 MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreUnset);
706 log_store()->UnsetAlternateOngoingLogStore();
707 OpenNewLog();
708 RecordUserLogStoreState(kUnsetPostSendLogsState);
709 return;
710 }
711
712 // Fast startup and logout case. We flush all histograms and discard the
713 // current log. This is to prevent histograms captured during the user
714 // session from leaking into local state logs.
715 // TODO(crbug.com/40245274): Consider not flushing histograms here.
716
717 // Discard histograms.
718 DiscardingFlattener flattener;
719 base::HistogramSnapshotManager histogram_snapshot_manager(&flattener);
720 delegating_provider_.RecordHistogramSnapshots(&histogram_snapshot_manager);
721 base::StatisticsRecorder::PrepareDeltas(
722 /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
723 /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
724 &histogram_snapshot_manager);
725
726 // Discard the current log and don't store it.
727 CHECK(current_log_);
728 current_log_.reset();
729
730 log_store()->UnsetAlternateOngoingLogStore();
731 RecordUserLogStoreState(kUnsetPreSendLogsState);
732 }
733
HasUserLogStore()734 bool MetricsService::HasUserLogStore() {
735 return log_store()->has_alternate_ongoing_log_store();
736 }
737
InitPerUserMetrics()738 void MetricsService::InitPerUserMetrics() {
739 client_->InitPerUserMetrics();
740 }
741
GetCurrentUserMetricsConsent() const742 std::optional<bool> MetricsService::GetCurrentUserMetricsConsent() const {
743 return client_->GetCurrentUserMetricsConsent();
744 }
745
GetCurrentUserId() const746 std::optional<std::string> MetricsService::GetCurrentUserId() const {
747 return client_->GetCurrentUserId();
748 }
749
UpdateCurrentUserMetricsConsent(bool user_metrics_consent)750 void MetricsService::UpdateCurrentUserMetricsConsent(
751 bool user_metrics_consent) {
752 client_->UpdateCurrentUserMetricsConsent(user_metrics_consent);
753 }
754 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
755
756 #if BUILDFLAG(IS_CHROMEOS)
ResetClientId()757 void MetricsService::ResetClientId() {
758 // Pref must be cleared in order for ForceClientIdCreation to generate a new
759 // client ID.
760 local_state_->ClearPref(prefs::kMetricsClientID);
761 local_state_->ClearPref(prefs::kMetricsLogFinalizedRecordId);
762 local_state_->ClearPref(prefs::kMetricsLogRecordId);
763 state_manager_->ForceClientIdCreation();
764 client_->SetMetricsClientId(state_manager_->client_id());
765 }
766 #endif // BUILDFLAG(IS_CHROMEOS)
767
768 variations::SyntheticTrialRegistry*
GetSyntheticTrialRegistry()769 MetricsService::GetSyntheticTrialRegistry() {
770 return client_->GetSyntheticTrialRegistry();
771 }
772
GetInitializationDelay()773 base::TimeDelta MetricsService::GetInitializationDelay() {
774 return base::Seconds(
775 client_->ShouldStartUpFastForTesting() ? 0 : kInitializationDelaySeconds);
776 }
777
GetUpdateLastAliveTimestampDelay()778 base::TimeDelta MetricsService::GetUpdateLastAliveTimestampDelay() {
779 return base::Seconds(kUpdateAliveTimestampSeconds);
780 }
781
StageCurrentLogForTest()782 bool MetricsService::StageCurrentLogForTest() {
783 CloseCurrentLog(/*async=*/false,
784 MetricsLogsEventManager::CreateReason::kUnknown);
785
786 MetricsLogStore* const log_store = reporting_service_.metrics_log_store();
787 log_store->StageNextLog();
788 if (!log_store->has_staged_log())
789 return false;
790
791 OpenNewLog();
792 return true;
793 }
794
795 //------------------------------------------------------------------------------
796 // private methods
797 //------------------------------------------------------------------------------
798
799 //------------------------------------------------------------------------------
800 // Initialization methods
801
InitializeMetricsState()802 void MetricsService::InitializeMetricsState() {
803 SCOPED_UMA_HISTOGRAM_TIMER_MICROS("UMA.MetricsService.Initialize.Time");
804
805 const int64_t buildtime = MetricsLog::GetBuildTime();
806 const std::string version = client_->GetVersionString();
807
808 bool version_changed = false;
809 EnvironmentRecorder recorder(local_state_);
810 int64_t previous_buildtime = recorder.GetLastBuildtime();
811 std::string previous_version = recorder.GetLastVersion();
812 if (previous_buildtime != buildtime || previous_version != version) {
813 recorder.SetBuildtimeAndVersion(buildtime, version);
814 version_changed = true;
815 }
816
817 session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
818
819 StabilityMetricsProvider provider(local_state_);
820 const bool was_last_shutdown_clean = WasLastShutdownClean();
821 if (!was_last_shutdown_clean) {
822 provider.LogCrash(
823 state_manager_->clean_exit_beacon()->browser_last_live_timestamp());
824 #if BUILDFLAG(IS_ANDROID)
825 if (!state_manager_->is_foreground_session()) {
826 // Android can have background sessions in which the app may not come to
827 // the foreground, so signal that Chrome should stop watching for crashes
828 // here. This ensures that the termination of such sessions is not
829 // considered a crash. If and when the app enters the foreground, Chrome
830 // starts watching for crashes via MetricsService::OnAppEnterForeground().
831 //
832 // TODO(crbug/1232027): Such sessions do not yet exist on iOS. When they
833 // do, it may not be possible to know at this point whether a session is a
834 // background session.
835 //
836 // TODO(crbug.com/40788576): On WebLayer, it is not possible to know
837 // whether it's a background session at this point.
838 //
839 // TODO(crbug.com/40196247): Ditto for WebView.
840 state_manager_->clean_exit_beacon()->WriteBeaconValue(true);
841 }
842 #endif // BUILDFLAG(IS_ANDROID)
843 }
844
845 // HasPreviousSessionData is called first to ensure it is never bypassed.
846 const bool is_initial_stability_log_required =
847 delegating_provider_.HasPreviousSessionData() || !was_last_shutdown_clean;
848 bool has_initial_stability_log = false;
849 if (is_initial_stability_log_required) {
850 // If the previous session didn't exit cleanly, or if any provider
851 // explicitly requests it, prepare an initial stability log -
852 // provided UMA is enabled.
853 if (state_manager_->IsMetricsReportingEnabled()) {
854 has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
855 }
856 }
857
858 // If the version changed, but no initial stability log was generated, clear
859 // the stability stats from the previous version (so that they don't get
860 // attributed to the current version). This could otherwise happen due to a
861 // number of different edge cases, such as if the last version crashed before
862 // it could save off a system profile or if UMA reporting is disabled (which
863 // normally results in stats being accumulated).
864 if (version_changed && !has_initial_stability_log)
865 ClearSavedStabilityMetrics();
866
867 // If the version changed, the system profile is obsolete and needs to be
868 // cleared. This is to avoid the stability data misattribution that could
869 // occur if the current version crashed before saving its own system profile.
870 // Note however this clearing occurs only after preparing the initial
871 // stability log, an operation that requires the previous version's system
872 // profile. At this point, stability metrics pertaining to the previous
873 // version have been cleared.
874 if (version_changed)
875 recorder.ClearEnvironmentFromPrefs();
876
877 // Update session ID.
878 ++session_id_;
879 local_state_->SetInteger(prefs::kMetricsSessionID, session_id_);
880
881 // Notify stability metrics providers about the launch.
882 provider.LogLaunch();
883
884 // Call GetUptimes() for the first time, thus allowing all later calls
885 // to record incremental uptimes accurately.
886 base::TimeDelta ignored_uptime_parameter;
887 base::TimeDelta startup_uptime;
888 GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter);
889 DCHECK_EQ(0, startup_uptime.InMicroseconds());
890 }
891
OnUserAction(const std::string & action,base::TimeTicks action_time)892 void MetricsService::OnUserAction(const std::string& action,
893 base::TimeTicks action_time) {
894 current_log_->RecordUserAction(action, action_time);
895 HandleIdleSinceLastTransmission(false);
896 }
897
FinishedInitTask()898 void MetricsService::FinishedInitTask() {
899 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
900 state_ = INIT_TASK_DONE;
901 rotation_scheduler_->InitTaskComplete();
902 }
903
GetUptimes(PrefService * pref,base::TimeDelta * incremental_uptime,base::TimeDelta * uptime)904 void MetricsService::GetUptimes(PrefService* pref,
905 base::TimeDelta* incremental_uptime,
906 base::TimeDelta* uptime) {
907 base::TimeTicks now = base::TimeTicks::Now();
908 // If this is the first call, init |first_updated_time_| and
909 // |last_updated_time_|.
910 if (last_updated_time_.is_null()) {
911 first_updated_time_ = now;
912 last_updated_time_ = now;
913 }
914 *incremental_uptime = now - last_updated_time_;
915 *uptime = now - first_updated_time_;
916 last_updated_time_ = now;
917 }
918
919 //------------------------------------------------------------------------------
920 // Recording control methods
921
OpenNewLog(bool call_providers)922 void MetricsService::OpenNewLog(bool call_providers) {
923 CHECK(!current_log_);
924
925 current_log_ = CreateLog(MetricsLog::ONGOING_LOG);
926 if (call_providers) {
927 delegating_provider_.OnDidCreateMetricsLog();
928 }
929
930 DCHECK_NE(CONSTRUCTED, state_);
931 if (state_ == INITIALIZED) {
932 // We only need to schedule that run once.
933 state_ = INIT_TASK_SCHEDULED;
934
935 base::TimeDelta initialization_delay = GetInitializationDelay();
936 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
937 FROM_HERE,
938 base::BindOnce(&MetricsService::StartInitTask,
939 self_ptr_factory_.GetWeakPtr()),
940 initialization_delay);
941
942 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
943 FROM_HERE,
944 base::BindOnce(&MetricsService::PrepareProviderMetricsTask,
945 self_ptr_factory_.GetWeakPtr()),
946 2 * initialization_delay);
947 }
948 }
949
950 MetricsService::FinalizedLog::FinalizedLog() = default;
951 MetricsService::FinalizedLog::~FinalizedLog() = default;
952 MetricsService::FinalizedLog::FinalizedLog(FinalizedLog&& other) = default;
953 MetricsService::FinalizedLog& MetricsService::FinalizedLog::operator=(
954 FinalizedLog&& other) = default;
955
MetricsLogHistogramWriter(MetricsLog * log)956 MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
957 MetricsLog* log)
958 : MetricsLogHistogramWriter(log,
959 base::Histogram::kUmaTargetedHistogramFlag) {}
960
MetricsLogHistogramWriter(MetricsLog * log,base::HistogramBase::Flags required_flags)961 MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
962 MetricsLog* log,
963 base::HistogramBase::Flags required_flags)
964 : required_flags_(required_flags),
965 flattener_(std::make_unique<IndependentFlattener>(log)),
966 histogram_snapshot_manager_(
967 std::make_unique<base::HistogramSnapshotManager>(flattener_.get())),
968 snapshot_transaction_id_(0) {}
969
970 MetricsService::MetricsLogHistogramWriter::~MetricsLogHistogramWriter() =
971 default;
972
973 void MetricsService::MetricsLogHistogramWriter::
SnapshotStatisticsRecorderDeltas()974 SnapshotStatisticsRecorderDeltas() {
975 SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.SnapshotDeltasTime");
976 snapshot_transaction_id_ = base::StatisticsRecorder::PrepareDeltas(
977 /*include_persistent=*/true,
978 /*flags_to_set=*/base::Histogram::kNoFlags, required_flags_,
979 histogram_snapshot_manager_.get());
980 }
981
982 void MetricsService::MetricsLogHistogramWriter::
SnapshotStatisticsRecorderUnloggedSamples()983 SnapshotStatisticsRecorderUnloggedSamples() {
984 snapshot_transaction_id_ = base::StatisticsRecorder::SnapshotUnloggedSamples(
985 required_flags_, histogram_snapshot_manager_.get());
986 }
987
IndependentMetricsLoader(std::unique_ptr<MetricsLog> log,std::string app_version,std::string signing_key)988 MetricsService::IndependentMetricsLoader::IndependentMetricsLoader(
989 std::unique_ptr<MetricsLog> log,
990 std::string app_version,
991 std::string signing_key)
992 : log_(std::move(log)),
993 flattener_(new IndependentFlattener(log_.get())),
994 snapshot_manager_(new base::HistogramSnapshotManager(flattener_.get())),
995 app_version_(std::move(app_version)),
996 signing_key_(std::move(signing_key)) {
997 CHECK(log_);
998 CHECK_EQ(log_->log_type(), MetricsLog::INDEPENDENT_LOG);
999 }
1000
1001 MetricsService::IndependentMetricsLoader::~IndependentMetricsLoader() = default;
1002
Run(base::OnceCallback<void (bool)> done_callback,MetricsProvider * metrics_provider)1003 void MetricsService::IndependentMetricsLoader::Run(
1004 base::OnceCallback<void(bool)> done_callback,
1005 MetricsProvider* metrics_provider) {
1006 CHECK(!run_called_);
1007 run_called_ = true;
1008
1009 metrics_provider->ProvideIndependentMetrics(
1010 // Unretained is safe because this callback is either called before
1011 // |done_callback|, or in |done_callback|. Either case is fine because
1012 // |done_callback| owns |this|.
1013 base::BindOnce(&MetricsService::IndependentMetricsLoader::FinalizeLog,
1014 base::Unretained(this)),
1015 std::move(done_callback), log_->uma_proto(), snapshot_manager_.get());
1016 }
1017
FinalizeLog()1018 void MetricsService::IndependentMetricsLoader::FinalizeLog() {
1019 CHECK(run_called_);
1020 CHECK(!finalize_log_called_);
1021 finalize_log_called_ = true;
1022
1023 // Release |snapshot_manager_| and then |flattener_| to prevent dangling
1024 // pointers, since |log_| will be released in MetricsService::FinalizeLog().
1025 snapshot_manager_.reset();
1026 flattener_.reset();
1027
1028 // Note that the close_time param must not be set for independent logs.
1029 finalized_log_ = MetricsService::FinalizeLog(
1030 std::move(log_), /*truncate_events=*/false, /*close_time=*/std::nullopt,
1031 app_version_, signing_key_);
1032 }
1033
HasFinalizedLog()1034 bool MetricsService::IndependentMetricsLoader::HasFinalizedLog() {
1035 return finalize_log_called_ && !release_finalized_log_called_;
1036 }
1037
1038 MetricsService::FinalizedLog
ReleaseFinalizedLog()1039 MetricsService::IndependentMetricsLoader::ReleaseFinalizedLog() {
1040 CHECK(HasFinalizedLog());
1041
1042 release_finalized_log_called_ = true;
1043 return std::move(finalized_log_);
1044 }
1045
StartInitTask()1046 void MetricsService::StartInitTask() {
1047 delegating_provider_.AsyncInit(base::BindOnce(
1048 &MetricsService::FinishedInitTask, self_ptr_factory_.GetWeakPtr()));
1049 }
1050
CloseCurrentLog(bool async,MetricsLogsEventManager::CreateReason reason,base::OnceClosure log_stored_callback)1051 void MetricsService::CloseCurrentLog(
1052 bool async,
1053 MetricsLogsEventManager::CreateReason reason,
1054 base::OnceClosure log_stored_callback) {
1055 if (!current_log_) {
1056 return;
1057 }
1058
1059 // If a persistent allocator is in use, update its internal histograms (such
1060 // as how much memory is being used) before reporting.
1061 base::PersistentHistogramAllocator* allocator =
1062 base::GlobalHistogramAllocator::Get();
1063 if (allocator)
1064 allocator->UpdateTrackingHistograms();
1065
1066 // Put incremental data (histogram deltas, and realtime stats deltas) at the
1067 // end of all log transmissions (initial log handles this separately).
1068 // RecordIncrementalStabilityElements only exists on the derived
1069 // MetricsLog class.
1070 std::unique_ptr<MetricsLog> current_log(std::move(current_log_));
1071 RecordCurrentEnvironment(current_log.get(), /*complete=*/true);
1072 base::TimeDelta incremental_uptime;
1073 base::TimeDelta uptime;
1074 GetUptimes(local_state_, &incremental_uptime, &uptime);
1075 current_log->RecordCurrentSessionData(incremental_uptime, uptime,
1076 &delegating_provider_, local_state_);
1077 current_log->AssignFinalizedRecordId(local_state_);
1078
1079 auto log_histogram_writer =
1080 std::make_unique<MetricsLogHistogramWriter>(current_log.get());
1081
1082 // Let metrics providers provide histogram snapshots independently if they
1083 // have any. This is done synchronously.
1084 delegating_provider_.RecordHistogramSnapshots(
1085 log_histogram_writer->histogram_snapshot_manager());
1086
1087 MetricsLog::LogType log_type = current_log->log_type();
1088 CHECK_EQ(log_type, MetricsLog::ONGOING_LOG);
1089 ChromeUserMetricsExtension::RealLocalTime close_time =
1090 current_log->GetCurrentClockTime(/*record_time_zone=*/true);
1091 std::string signing_key = log_store()->GetSigningKeyForLogType(log_type);
1092 std::string current_app_version = client_->GetVersionString();
1093
1094 #if !BUILDFLAG(IS_ANDROID)
1095 if (base::FeatureList::IsEnabled(
1096 features::kMetricsServiceDeltaSnapshotInBg)) {
1097 // If this is an async periodic log, and the browser is about to be shut
1098 // down (determined by KeepAliveRegistry::IsShuttingDown(), indicating that
1099 // there is nothing else to keep the browser alive), then do the work
1100 // synchronously instead. Otherwise, creating a ScopedKeepAlive below while
1101 // the KeepAliveRegistry has already started shutting down will trigger a
1102 // CHECK. Alternatively, the ScopedKeepAlive below could be omitted when the
1103 // KeepAliveRegistry is shutting down, but since the browser is shutting
1104 // down soon, then it is likely that the asynchronous task to close the
1105 // current the log will be cut short, causing data loss.
1106 if (async && KeepAliveRegistry::GetInstance()->IsShuttingDown()) {
1107 async = false;
1108 }
1109 }
1110 #endif
1111
1112 if (async) {
1113 if (base::FeatureList::IsEnabled(
1114 features::kMetricsServiceDeltaSnapshotInBg)) {
1115 // In this mode, we perform the full "delta snapshot" (snapshotting
1116 // unlogged samples and marking them as logged) in the background, in
1117 // contrast to snapshotting unlogged samples in the background and marking
1118 // them as logged when back on the main thread, as is done in the else
1119 // branch.
1120
1121 auto background_task = base::BindOnce(
1122 &MetricsService::SnapshotDeltasAndFinalizeLog,
1123 std::move(log_histogram_writer), std::move(current_log),
1124 /*truncate_events=*/true, std::move(close_time),
1125 std::move(current_app_version), std::move(signing_key));
1126 auto reply_task = base::BindOnce(&MetricsService::StoreFinalizedLog,
1127 self_ptr_factory_.GetWeakPtr(), log_type,
1128 reason, std::move(log_stored_callback));
1129
1130 #if !BUILDFLAG(IS_ANDROID)
1131 // Prevent the browser from shutting down while creating the log in the
1132 // background. This is done by creating a ScopedKeepAlive that is only
1133 // destroyed after the log has been stored. Not used on Android because it
1134 // has no shutdown code path.
1135 reply_task = std::move(reply_task)
1136 .Then(base::BindOnce(
1137 [](std::unique_ptr<ScopedKeepAlive>) {
1138 // This function does nothing but keep the
1139 // ScopedKeepAlive param alive until we have
1140 // finished storing the log.
1141 },
1142 std::make_unique<ScopedKeepAlive>(
1143 KeepAliveOrigin::UMA_LOG,
1144 KeepAliveRestartOption::DISABLED)));
1145 #endif // !BUILDFLAG(IS_ANDROID)
1146
1147 base::ThreadPool::PostTaskAndReplyWithResult(
1148 FROM_HERE,
1149 {base::TaskPriority::USER_BLOCKING,
1150 base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
1151 std::move(background_task), std::move(reply_task));
1152 } else {
1153 // To finalize the log asynchronously, we snapshot the unlogged samples of
1154 // histograms and fill them into the log, without actually marking the
1155 // samples as logged. We only mark them as logged after running the main
1156 // thread reply task to store the log. This way, we will not lose the
1157 // samples in case Chrome closes while the background task is running.
1158 // Note that while this async log is being finalized, it is possible that
1159 // another log is finalized and stored synchronously, which could
1160 // potentially cause the same samples to be in two different logs, and
1161 // hence sent twice. To prevent this, if a synchronous log is stored while
1162 // the async one is being finalized, we discard the async log as it would
1163 // be a subset of the synchronous one (in terms of histograms). For more
1164 // details, see MaybeCleanUpAndStoreFinalizedLog().
1165 //
1166 // TODO(crbug/1052796): Find a way to save the other data such as user
1167 // actions and omnibox events when we discard an async log.
1168 MetricsLogHistogramWriter* log_histogram_writer_ptr =
1169 log_histogram_writer.get();
1170 base::ThreadPool::PostTaskAndReplyWithResult(
1171 FROM_HERE,
1172 // CONTINUE_ON_SHUTDOWN because the work done is only useful once the
1173 // reply task is run (and there are no side effects). So, no need to
1174 // block shutdown since the reply task won't be run anyway.
1175 // NOTE: If attempting to change the USER_BLOCKING priority, do a
1176 // study on the impact first since it might affect the number of logs
1177 // being uploaded (which might have secondary effects, e.g. on metrics
1178 // that rely on number of logs uploaded).
1179 {base::TaskPriority::USER_BLOCKING,
1180 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
1181 base::BindOnce(&MetricsService::SnapshotUnloggedSamplesAndFinalizeLog,
1182 log_histogram_writer_ptr, std::move(current_log),
1183 /*truncate_events=*/true, std::move(close_time),
1184 std::move(current_app_version),
1185 std::move(signing_key)),
1186 base::BindOnce(&MetricsService::MaybeCleanUpAndStoreFinalizedLog,
1187 self_ptr_factory_.GetWeakPtr(),
1188 std::move(log_histogram_writer), log_type, reason,
1189 std::move(log_stored_callback)));
1190 async_ongoing_log_posted_time_ = base::TimeTicks::Now();
1191 }
1192 } else {
1193 FinalizedLog finalized_log = SnapshotDeltasAndFinalizeLog(
1194 std::move(log_histogram_writer), std::move(current_log),
1195 /*truncate_events=*/true, std::move(close_time),
1196 std::move(current_app_version), std::move(signing_key));
1197 StoreFinalizedLog(log_type, reason, std::move(log_stored_callback),
1198 std::move(finalized_log));
1199 }
1200 }
1201
StoreFinalizedLog(MetricsLog::LogType log_type,MetricsLogsEventManager::CreateReason reason,base::OnceClosure done_callback,FinalizedLog finalized_log)1202 void MetricsService::StoreFinalizedLog(
1203 MetricsLog::LogType log_type,
1204 MetricsLogsEventManager::CreateReason reason,
1205 base::OnceClosure done_callback,
1206 FinalizedLog finalized_log) {
1207 log_store()->StoreLogInfo(std::move(finalized_log.log_info),
1208 finalized_log.uncompressed_log_size, log_type,
1209 reason);
1210 std::move(done_callback).Run();
1211 }
1212
MaybeCleanUpAndStoreFinalizedLog(std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,MetricsLog::LogType log_type,MetricsLogsEventManager::CreateReason reason,base::OnceClosure done_callback,FinalizedLog finalized_log)1213 void MetricsService::MaybeCleanUpAndStoreFinalizedLog(
1214 std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,
1215 MetricsLog::LogType log_type,
1216 MetricsLogsEventManager::CreateReason reason,
1217 base::OnceClosure done_callback,
1218 FinalizedLog finalized_log) {
1219 UMA_HISTOGRAM_TIMES("UMA.MetricsService.PeriodicOngoingLog.ReplyTime",
1220 base::TimeTicks::Now() - async_ongoing_log_posted_time_);
1221
1222 // Store the finalized log only if the StatisticRecorder's last transaction ID
1223 // is the same as the one from |log_histogram_writer|. If they are not the
1224 // same, then it indicates that another log was created while creating
1225 // |finalized_log| (that log would be a superset of |finalized_log| in terms
1226 // of histograms, so we discard |finalized_log| by not storing it).
1227 //
1228 // TODO(crbug/1052796): Find a way to save the other data such as user actions
1229 // and omnibox events when we discard |finalized_log|.
1230 //
1231 // Note that the call to StatisticsRecorder::GetLastSnapshotTransactionId()
1232 // here should not have to wait for a lock since there should not be any async
1233 // logs being created (|rotation_scheduler_| is only re-scheduled at the end
1234 // of this method).
1235 bool should_store_log =
1236 (base::StatisticsRecorder::GetLastSnapshotTransactionId() ==
1237 log_histogram_writer->snapshot_transaction_id());
1238 base::UmaHistogramBoolean("UMA.MetricsService.ShouldStoreAsyncLog",
1239 should_store_log);
1240
1241 if (!should_store_log) {
1242 // We still need to run |done_callback| even if we do not store the log.
1243 std::move(done_callback).Run();
1244 return;
1245 }
1246
1247 SCOPED_UMA_HISTOGRAM_TIMER(
1248 "UMA.MetricsService.MaybeCleanUpAndStoreFinalizedLog.Time");
1249
1250 log_histogram_writer->histogram_snapshot_manager()
1251 ->MarkUnloggedSamplesAsLogged();
1252 StoreFinalizedLog(log_type, reason, std::move(done_callback),
1253 std::move(finalized_log));
1254 }
1255
PushPendingLogsToPersistentStorage(MetricsLogsEventManager::CreateReason reason)1256 void MetricsService::PushPendingLogsToPersistentStorage(
1257 MetricsLogsEventManager::CreateReason reason) {
1258 if (IsTooEarlyToCloseLog()) {
1259 return;
1260 }
1261
1262 base::UmaHistogramBoolean("UMA.MetricsService.PendingOngoingLog",
1263 pending_ongoing_log_);
1264
1265 // Close and store a log synchronously because this is usually called in
1266 // critical code paths (e.g., shutdown) where we may not have time to run
1267 // background tasks.
1268 CloseCurrentLog(/*async=*/false, reason);
1269 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
1270 }
1271
1272 //------------------------------------------------------------------------------
1273 // Transmission of logs methods
1274
StartSchedulerIfNecessary()1275 void MetricsService::StartSchedulerIfNecessary() {
1276 // Never schedule cutting or uploading of logs in test mode.
1277 if (test_mode_active_)
1278 return;
1279
1280 // Even if reporting is disabled, the scheduler is needed to trigger the
1281 // creation of the first ongoing log, which must be done in order for any logs
1282 // to be persisted on shutdown or backgrounding.
1283 if (recording_active() && (reporting_active() || state_ < SENDING_LOGS)) {
1284 rotation_scheduler_->Start();
1285 reporting_service_.Start();
1286 }
1287 }
1288
StartScheduledUpload()1289 void MetricsService::StartScheduledUpload() {
1290 DVLOG(1) << "StartScheduledUpload";
1291 DCHECK(state_ >= INIT_TASK_DONE);
1292
1293 // If we're getting no notifications, then the log won't have much in it, and
1294 // it's possible the computer is about to go to sleep, so don't upload and
1295 // stop the scheduler.
1296 // If recording has been turned off, the scheduler doesn't need to run.
1297 // If reporting is off, proceed if the first ongoing log hasn't been created,
1298 // since that has to happen in order for logs to be cut and stored when
1299 // persisting.
1300 // TODO(stuartmorgan): Call Stop() on the scheduler when reporting and/or
1301 // recording are turned off instead of letting it fire and then aborting.
1302 if (idle_since_last_transmission_ || !recording_active() ||
1303 (!reporting_active() && state_ >= SENDING_LOGS)) {
1304 rotation_scheduler_->Stop();
1305 rotation_scheduler_->RotationFinished();
1306 return;
1307 }
1308
1309 // The first ongoing log should be collected prior to sending any unsent logs.
1310 if (state_ == INIT_TASK_DONE) {
1311 client_->CollectFinalMetricsForLog(
1312 base::BindOnce(&MetricsService::OnFinalLogInfoCollectionDone,
1313 self_ptr_factory_.GetWeakPtr()));
1314 return;
1315 }
1316
1317 // If there are unsent logs, send the next one. If not, start the asynchronous
1318 // process of finalizing the current log for upload.
1319 if (has_unsent_logs()) {
1320 reporting_service_.Start();
1321 rotation_scheduler_->RotationFinished();
1322 } else {
1323 // There are no logs left to send, so start creating a new one.
1324 client_->CollectFinalMetricsForLog(
1325 base::BindOnce(&MetricsService::OnFinalLogInfoCollectionDone,
1326 self_ptr_factory_.GetWeakPtr()));
1327 }
1328 }
1329
OnFinalLogInfoCollectionDone()1330 void MetricsService::OnFinalLogInfoCollectionDone() {
1331 DVLOG(1) << "OnFinalLogInfoCollectionDone";
1332 DCHECK(state_ >= INIT_TASK_DONE);
1333 state_ = SENDING_LOGS;
1334
1335 // Abort if metrics were turned off during the final info gathering.
1336 if (!recording_active()) {
1337 rotation_scheduler_->Stop();
1338 rotation_scheduler_->RotationFinished();
1339 return;
1340 }
1341
1342 SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.PeriodicOngoingLog.CloseTime");
1343
1344 // There shouldn't be two periodic ongoing logs being finalized in the
1345 // background simultaneously. This is currently enforced because:
1346 // 1. Only periodic ongoing logs are finalized asynchronously (i.e., logs
1347 // created by the MetricsRotationScheduler).
1348 // 2. We only re-schedule the MetricsRotationScheduler after storing a
1349 // periodic ongoing log.
1350 //
1351 // TODO(crbug/1052796): Consider making it possible to have multiple
1352 // simultaneous async logs by having some queueing system (e.g., if we want
1353 // the log created when foregrounding Chrome to be async).
1354 DCHECK(!pending_ongoing_log_);
1355 pending_ongoing_log_ = true;
1356
1357 base::OnceClosure log_stored_callback =
1358 base::BindOnce(&MetricsService::OnAsyncPeriodicOngoingLogStored,
1359 self_ptr_factory_.GetWeakPtr());
1360 CloseCurrentLog(/*async=*/true,
1361 MetricsLogsEventManager::CreateReason::kPeriodic,
1362 std::move(log_stored_callback));
1363 OpenNewLog(/*call_providers=*/false);
1364 }
1365
OnAsyncPeriodicOngoingLogStored()1366 void MetricsService::OnAsyncPeriodicOngoingLogStored() {
1367 pending_ongoing_log_ = false;
1368
1369 // Call OnDidCreateMetricsLog() after storing a log instead of directly after
1370 // opening a log. Otherwise, the async log that was created would potentially
1371 // have mistakenly snapshotted the histograms intended for the newly opened
1372 // log.
1373 delegating_provider_.OnDidCreateMetricsLog();
1374
1375 // Trim and store unsent logs, including the log that was just closed, so that
1376 // they're not lost in case of a crash before upload time. However, the
1377 // in-memory log store is unchanged. I.e., logs that are trimmed will still be
1378 // available in memory. This is to give the log that was just created a chance
1379 // to be sent in case it is trimmed. After uploading (whether successful or
1380 // not), the log store is trimmed and stored again, and at that time, the
1381 // in-memory log store will be updated.
1382 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/false);
1383
1384 // Do not re-schedule if metrics were turned off while finalizing the log.
1385 if (!recording_active()) {
1386 rotation_scheduler_->Stop();
1387 rotation_scheduler_->RotationFinished();
1388 } else {
1389 // Only re-schedule |rotation_scheduler_| *after* the log was stored to
1390 // ensure that only one log is created asynchronously at a time.
1391 reporting_service_.Start();
1392 rotation_scheduler_->RotationFinished();
1393 HandleIdleSinceLastTransmission(true);
1394 }
1395 }
1396
PrepareInitialStabilityLog(const std::string & prefs_previous_version)1397 bool MetricsService::PrepareInitialStabilityLog(
1398 const std::string& prefs_previous_version) {
1399 DCHECK_EQ(CONSTRUCTED, state_);
1400
1401 constexpr MetricsLog::LogType log_type = MetricsLog::INITIAL_STABILITY_LOG;
1402 std::unique_ptr<MetricsLog> initial_stability_log = CreateLog(log_type);
1403
1404 // Do not call OnDidCreateMetricsLog here because the stability log describes
1405 // stats from the _previous_ session.
1406
1407 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(local_state_))
1408 return false;
1409
1410 initial_stability_log->RecordPreviousSessionData(&delegating_provider_,
1411 local_state_);
1412 initial_stability_log->AssignFinalizedRecordId(local_state_);
1413
1414 auto log_histogram_writer = std::make_unique<MetricsLogHistogramWriter>(
1415 initial_stability_log.get(), base::Histogram::kUmaStabilityHistogramFlag);
1416
1417 // Add a beacon to this record to indicate that it's part of the initial
1418 // stability log.
1419 UMA_STABILITY_HISTOGRAM_BOOLEAN("UMA.InitialStabilityRecordBeacon", true);
1420
1421 // Let metrics providers provide histogram snapshots independently if they
1422 // have any. This is done synchronously.
1423 delegating_provider_.RecordInitialHistogramSnapshots(
1424 log_histogram_writer->histogram_snapshot_manager());
1425
1426 std::string signing_key = log_store()->GetSigningKeyForLogType(log_type);
1427
1428 // Synchronously create the initial stability log in order to ensure that the
1429 // stability histograms are filled into this specific log. Note that the
1430 // close_time param must not be set for initial stability logs.
1431 FinalizedLog finalized_log = SnapshotDeltasAndFinalizeLog(
1432 std::move(log_histogram_writer), std::move(initial_stability_log),
1433 /*truncate_events=*/false, /*close_time=*/std::nullopt,
1434 client_->GetVersionString(), std::move(signing_key));
1435 StoreFinalizedLog(log_type, MetricsLogsEventManager::CreateReason::kStability,
1436 base::DoNothing(), std::move(finalized_log));
1437
1438 // Store unsent logs, including the stability log that was just saved, so
1439 // that they're not lost in case of a crash before upload time.
1440 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
1441
1442 return true;
1443 }
1444
RegisterMetricsProvider(std::unique_ptr<MetricsProvider> provider)1445 void MetricsService::RegisterMetricsProvider(
1446 std::unique_ptr<MetricsProvider> provider) {
1447 DCHECK_EQ(CONSTRUCTED, state_);
1448 delegating_provider_.RegisterMetricsProvider(std::move(provider));
1449 }
1450
CheckForClonedInstall()1451 void MetricsService::CheckForClonedInstall() {
1452 state_manager_->CheckForClonedInstall();
1453 }
1454
ShouldResetClientIdsOnClonedInstall()1455 bool MetricsService::ShouldResetClientIdsOnClonedInstall() {
1456 return state_manager_->ShouldResetClientIdsOnClonedInstall();
1457 }
1458
CreateLog(MetricsLog::LogType log_type)1459 std::unique_ptr<MetricsLog> MetricsService::CreateLog(
1460 MetricsLog::LogType log_type) {
1461 auto new_metrics_log = std::make_unique<MetricsLog>(
1462 state_manager_->client_id(), session_id_, log_type, client_);
1463 new_metrics_log->AssignRecordId(local_state_);
1464
1465 #if BUILDFLAG(IS_CHROMEOS_ASH)
1466 std::optional<std::string> user_id = GetCurrentUserId();
1467 if (user_id.has_value())
1468 new_metrics_log->SetUserId(user_id.value());
1469 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
1470
1471 return new_metrics_log;
1472 }
1473
AddLogsObserver(MetricsLogsEventManager::Observer * observer)1474 void MetricsService::AddLogsObserver(
1475 MetricsLogsEventManager::Observer* observer) {
1476 logs_event_manager_.AddObserver(observer);
1477 }
1478
RemoveLogsObserver(MetricsLogsEventManager::Observer * observer)1479 void MetricsService::RemoveLogsObserver(
1480 MetricsLogsEventManager::Observer* observer) {
1481 logs_event_manager_.RemoveObserver(observer);
1482 }
1483
AddEnablementObserver(const base::RepeatingCallback<void (bool)> & observer)1484 base::CallbackListSubscription MetricsService::AddEnablementObserver(
1485 const base::RepeatingCallback<void(bool)>& observer) {
1486 return enablement_observers_.Add(observer);
1487 }
1488
SetPersistentSystemProfile(const std::string & serialized_proto,bool complete)1489 void MetricsService::SetPersistentSystemProfile(
1490 const std::string& serialized_proto,
1491 bool complete) {
1492 GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
1493 serialized_proto, complete);
1494 }
1495
1496 // static
RecordCurrentEnvironmentHelper(MetricsLog * log,PrefService * local_state,DelegatingProvider * delegating_provider)1497 std::string MetricsService::RecordCurrentEnvironmentHelper(
1498 MetricsLog* log,
1499 PrefService* local_state,
1500 DelegatingProvider* delegating_provider) {
1501 const SystemProfileProto& system_profile =
1502 log->RecordEnvironment(delegating_provider);
1503 EnvironmentRecorder recorder(local_state);
1504 return recorder.SerializeAndRecordEnvironmentToPrefs(system_profile);
1505 }
1506
RecordCurrentEnvironment(MetricsLog * log,bool complete)1507 void MetricsService::RecordCurrentEnvironment(MetricsLog* log, bool complete) {
1508 DCHECK(client_);
1509 std::string serialized_proto =
1510 RecordCurrentEnvironmentHelper(log, local_state_, &delegating_provider_);
1511
1512 SetPersistentSystemProfile(serialized_proto, complete);
1513 client_->OnEnvironmentUpdate(&serialized_proto);
1514
1515 // The call to SetPersistentSystemProfile() above will have written the
1516 // current system profile to persistent memory. Because it may span over
1517 // multiple pages, it is possible that the system profile may become corrupted
1518 // if only certain pages were flushed to disk. For example, say we overwrite
1519 // the persistent memory's system profile with a newer one, and that it spans
1520 // over two pages. Then, the OS flushes the second page, but not the first
1521 // page. If the device is shut down unexpectedly, e.g. due to a power outage,
1522 // then the first page will contain the beginning of the old system profile,
1523 // while the second page will contain the ending of the new system profile,
1524 // resulting in an unparsable system profile and rendering the whole file
1525 // useless. So, manually schedule a flush every time we overwrite the system
1526 // profile with a new one to ensure we don't ever get a corrupted one.
1527 if (base::FeatureList::IsEnabled(
1528 features::kFlushPersistentSystemProfileOnWrite)) {
1529 base::ThreadPool::PostTask(
1530 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
1531 base::BindOnce([]() {
1532 if (auto* allocator = base::GlobalHistogramAllocator::Get()) {
1533 // Ideally, we'd just call Flush() with the |sync| parameter set to
1534 // false on the main thread, but Windows does not support async
1535 // flushing, so do this synchronously on a background thread
1536 // instead.
1537 allocator->memory_allocator()->Flush(/*sync=*/true);
1538 }
1539 }));
1540 }
1541 }
1542
PrepareProviderMetricsLogDone(std::unique_ptr<IndependentMetricsLoader> loader,bool success)1543 void MetricsService::PrepareProviderMetricsLogDone(
1544 std::unique_ptr<IndependentMetricsLoader> loader,
1545 bool success) {
1546 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1547 DCHECK(independent_loader_active_);
1548 DCHECK(loader);
1549
1550 if (success) {
1551 // If not already done, finalize the log that was created independently by
1552 // the metrics provider.
1553 if (!loader->HasFinalizedLog()) {
1554 loader->FinalizeLog();
1555 }
1556
1557 StoreFinalizedLog(MetricsLog::INDEPENDENT_LOG,
1558 MetricsLogsEventManager::CreateReason::kIndependent,
1559 /*done_callback=*/base::DoNothing(),
1560 loader->ReleaseFinalizedLog());
1561 }
1562
1563 independent_loader_active_ = false;
1564 }
1565
PrepareProviderMetricsLog()1566 bool MetricsService::PrepareProviderMetricsLog() {
1567 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1568
1569 // If something is still pending, stop now and indicate that there is
1570 // still work to do.
1571 if (independent_loader_active_)
1572 return true;
1573
1574 // Check each provider in turn for data.
1575 for (auto& provider : delegating_provider_.GetProviders()) {
1576 if (provider->HasIndependentMetrics()) {
1577 // Create a new log. This will have some default values injected in it
1578 // but those will be overwritten when an embedded profile is extracted.
1579 constexpr MetricsLog::LogType log_type = MetricsLog::INDEPENDENT_LOG;
1580 std::unique_ptr<MetricsLog> log = CreateLog(log_type);
1581 log->AssignFinalizedRecordId(local_state_);
1582
1583 // Note that something is happening. This must be set before the
1584 // operation is requested in case the loader decides to do everything
1585 // immediately rather than as a background task.
1586 independent_loader_active_ = true;
1587
1588 // Give the new log to a loader for management and then run it on the
1589 // provider that has something to give. A copy of the pointer is needed
1590 // because the unique_ptr may get moved before the value can be used
1591 // to call Run().
1592 std::unique_ptr<IndependentMetricsLoader> loader =
1593 std::make_unique<IndependentMetricsLoader>(
1594 std::move(log), client_->GetVersionString(),
1595 log_store()->GetSigningKeyForLogType(log_type));
1596 IndependentMetricsLoader* loader_ptr = loader.get();
1597 loader_ptr->Run(
1598 base::BindOnce(&MetricsService::PrepareProviderMetricsLogDone,
1599 self_ptr_factory_.GetWeakPtr(), std::move(loader)),
1600 provider.get());
1601
1602 // Something was found so there may still be more work to do.
1603 return true;
1604 }
1605 }
1606
1607 // Nothing was found so indicate there is no more work to do.
1608 return false;
1609 }
1610
PrepareProviderMetricsTask()1611 void MetricsService::PrepareProviderMetricsTask() {
1612 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1613 bool found = PrepareProviderMetricsLog();
1614 base::TimeDelta next_check = found ? base::Seconds(5) : base::Minutes(15);
1615 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
1616 FROM_HERE,
1617 base::BindOnce(&MetricsService::PrepareProviderMetricsTask,
1618 self_ptr_factory_.GetWeakPtr()),
1619 next_check);
1620 }
1621
UpdateLastLiveTimestampTask()1622 void MetricsService::UpdateLastLiveTimestampTask() {
1623 state_manager_->clean_exit_beacon()->UpdateLastLiveTimestamp();
1624
1625 // Schecule the next update.
1626 StartUpdatingLastLiveTimestamp();
1627 }
1628
IsTooEarlyToCloseLog()1629 bool MetricsService::IsTooEarlyToCloseLog() {
1630 // When kMetricsServiceAllowEarlyLogClose is enabled, start closing logs as
1631 // soon as the first log is opened (|state_| is set to INIT_TASK_SCHEDULED
1632 // when the first log is opened, see OpenNewLog()). Otherwise, only start
1633 // closing logs when logs have started being sent.
1634 return base::FeatureList::IsEnabled(
1635 features::kMetricsServiceAllowEarlyLogClose)
1636 ? state_ < INIT_TASK_SCHEDULED
1637 : state_ < SENDING_LOGS;
1638 }
1639
OnClonedInstallDetected()1640 void MetricsService::OnClonedInstallDetected() {
1641 // Purge all logs, as they may come from a previous install. Unfortunately,
1642 // since the cloned install detector works asynchronously, it is possible that
1643 // this is called after logs were already sent. However, practically speaking,
1644 // this should not happen, since logs are only sent late into the session.
1645 reporting_service_.metrics_log_store()->Purge();
1646 }
1647
1648 // static
SnapshotDeltasAndFinalizeLog(std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,std::unique_ptr<MetricsLog> log,bool truncate_events,std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,std::string && current_app_version,std::string && signing_key)1649 MetricsService::FinalizedLog MetricsService::SnapshotDeltasAndFinalizeLog(
1650 std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,
1651 std::unique_ptr<MetricsLog> log,
1652 bool truncate_events,
1653 std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1654 std::string&& current_app_version,
1655 std::string&& signing_key) {
1656 log_histogram_writer->SnapshotStatisticsRecorderDeltas();
1657 return FinalizeLog(std::move(log), truncate_events, std::move(close_time),
1658 current_app_version, signing_key);
1659 }
1660
1661 // static
1662 MetricsService::FinalizedLog
SnapshotUnloggedSamplesAndFinalizeLog(MetricsLogHistogramWriter * log_histogram_writer,std::unique_ptr<MetricsLog> log,bool truncate_events,std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,std::string && current_app_version,std::string && signing_key)1663 MetricsService::SnapshotUnloggedSamplesAndFinalizeLog(
1664 MetricsLogHistogramWriter* log_histogram_writer,
1665 std::unique_ptr<MetricsLog> log,
1666 bool truncate_events,
1667 std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1668 std::string&& current_app_version,
1669 std::string&& signing_key) {
1670 log_histogram_writer->SnapshotStatisticsRecorderUnloggedSamples();
1671 return FinalizeLog(std::move(log), truncate_events, std::move(close_time),
1672 current_app_version, signing_key);
1673 }
1674
1675 // static
FinalizeLog(std::unique_ptr<MetricsLog> log,bool truncate_events,std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,const std::string & current_app_version,const std::string & signing_key)1676 MetricsService::FinalizedLog MetricsService::FinalizeLog(
1677 std::unique_ptr<MetricsLog> log,
1678 bool truncate_events,
1679 std::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1680 const std::string& current_app_version,
1681 const std::string& signing_key) {
1682 DCHECK(log->uma_proto()->has_record_id());
1683 std::string log_data;
1684 log->FinalizeLog(truncate_events, current_app_version, std::move(close_time),
1685 &log_data);
1686
1687 FinalizedLog finalized_log;
1688 finalized_log.uncompressed_log_size = log_data.size();
1689 finalized_log.log_info = std::make_unique<UnsentLogStore::LogInfo>();
1690 finalized_log.log_info->Init(log_data, signing_key, log->log_metadata());
1691 return finalized_log;
1692 }
1693
1694 } // namespace metrics
1695