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
SetExternalClientId(const std::string & id)483 void MetricsService::SetExternalClientId(const std::string& id) {
484 state_manager_->SetExternalClientId(id);
485 }
486
WasLastShutdownClean() const487 bool MetricsService::WasLastShutdownClean() const {
488 return state_manager_->clean_exit_beacon()->exited_cleanly();
489 }
490
EnableRecording()491 void MetricsService::EnableRecording() {
492 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
493
494 if (recording_state_ == ACTIVE)
495 return;
496 recording_state_ = ACTIVE;
497
498 state_manager_->ForceClientIdCreation();
499 client_->SetMetricsClientId(state_manager_->client_id());
500
501 if (!current_log_) {
502 OpenNewLog();
503 }
504
505 delegating_provider_.OnRecordingEnabled();
506
507 // Fill in the system profile in the log and persist it (to prefs, .pma
508 // and crashpad). This includes running the providers so that information
509 // like field trials and hardware info is provided. If Chrome crashes
510 // before this log is completed, the .pma file will have this system
511 // profile.
512 RecordCurrentEnvironment(current_log_.get(), /*complete=*/false);
513
514 base::RemoveActionCallback(action_callback_);
515 action_callback_ = base::BindRepeating(&MetricsService::OnUserAction,
516 base::Unretained(this));
517 base::AddActionCallback(action_callback_);
518
519 enablement_observers_.Notify(/*enabled=*/true);
520 }
521
DisableRecording()522 void MetricsService::DisableRecording() {
523 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
524
525 if (recording_state_ == INACTIVE)
526 return;
527 recording_state_ = INACTIVE;
528
529 base::RemoveActionCallback(action_callback_);
530
531 delegating_provider_.OnRecordingDisabled();
532
533 base::UmaHistogramBoolean("UMA.MetricsService.PendingOngoingLogOnDisable",
534 pending_ongoing_log_);
535 PushPendingLogsToPersistentStorage(
536 MetricsLogsEventManager::CreateReason::kServiceShutdown);
537
538 // Because histograms may still be emitted after the last log was closed, an
539 // independent log may be created in a future session in order to report
540 // those histograms. To ensure that this independent log contains histograms
541 // that we wish to appear in every log, call OnDidCreateMetricsLog().
542 delegating_provider_.OnDidCreateMetricsLog();
543
544 enablement_observers_.Notify(/*enabled=*/false);
545 }
546
recording_active() const547 bool MetricsService::recording_active() const {
548 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
549 return recording_state_ == ACTIVE;
550 }
551
reporting_active() const552 bool MetricsService::reporting_active() const {
553 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
554 return reporting_service_.reporting_active();
555 }
556
has_unsent_logs() const557 bool MetricsService::has_unsent_logs() const {
558 return reporting_service_.metrics_log_store()->has_unsent_logs();
559 }
560
IsMetricsReportingEnabled() const561 bool MetricsService::IsMetricsReportingEnabled() const {
562 return state_manager_->IsMetricsReportingEnabled();
563 }
564
HandleIdleSinceLastTransmission(bool in_idle)565 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
566 // If there wasn't a lot of action, maybe the computer was asleep, in which
567 // case, the log transmissions should have stopped. Here we start them up
568 // again.
569 if (!in_idle && idle_since_last_transmission_)
570 StartSchedulerIfNecessary();
571 idle_since_last_transmission_ = in_idle;
572 }
573
OnApplicationNotIdle()574 void MetricsService::OnApplicationNotIdle() {
575 if (recording_state_ == ACTIVE)
576 HandleIdleSinceLastTransmission(false);
577 }
578
579 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
OnAppEnterBackground(bool keep_recording_in_background)580 void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
581 is_in_foreground_ = false;
582 reporting_service_.SetIsInForegound(false);
583 if (!keep_recording_in_background) {
584 rotation_scheduler_->Stop();
585 reporting_service_.Stop();
586 }
587
588 state_manager_->LogHasSessionShutdownCleanly(true);
589 // Schedule a write, which happens on a different thread.
590 local_state_->CommitPendingWrite();
591
592 // Give providers a chance to persist histograms as part of being
593 // backgrounded.
594 delegating_provider_.OnAppEnterBackground();
595
596 // At this point, there's no way of knowing when the process will be killed,
597 // so this has to be treated similar to a shutdown, closing and persisting all
598 // logs. Unlike a shutdown, the state is primed to be ready to continue
599 // logging and uploading if the process does return.
600 if (recording_active() && !IsTooEarlyToCloseLog()) {
601 base::UmaHistogramBoolean(
602 "UMA.MetricsService.PendingOngoingLogOnBackgrounded",
603 pending_ongoing_log_);
604 #if BUILDFLAG(IS_ANDROID)
605 client_->MergeSubprocessHistograms();
606 #endif // BUILDFLAG(IS_ANDROID)
607 {
608 ScopedTerminationChecker scoped_termination_checker(
609 "UMA.MetricsService.OnBackgroundedScopedTerminationChecker");
610 PushPendingLogsToPersistentStorage(
611 MetricsLogsEventManager::CreateReason::kBackgrounded);
612 }
613 // Persisting logs closes the current log, so start recording a new log
614 // immediately to capture any background work that might be done before the
615 // process is killed.
616 OpenNewLog();
617 }
618 }
619
OnAppEnterForeground(bool force_open_new_log)620 void MetricsService::OnAppEnterForeground(bool force_open_new_log) {
621 is_in_foreground_ = true;
622 reporting_service_.SetIsInForegound(true);
623 state_manager_->LogHasSessionShutdownCleanly(false);
624 StartSchedulerIfNecessary();
625
626 if (force_open_new_log && recording_active() && !IsTooEarlyToCloseLog()) {
627 base::UmaHistogramBoolean(
628 "UMA.MetricsService.PendingOngoingLogOnForegrounded",
629 pending_ongoing_log_);
630 #if BUILDFLAG(IS_ANDROID)
631 client_->MergeSubprocessHistograms();
632 #endif // BUILDFLAG(IS_ANDROID)
633 // Because state_ >= SENDING_LOGS, PushPendingLogsToPersistentStorage()
634 // will close the log, allowing a new log to be opened.
635 PushPendingLogsToPersistentStorage(
636 MetricsLogsEventManager::CreateReason::kForegrounded);
637 OpenNewLog();
638 }
639 }
640 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
641
OnPageLoadStarted()642 void MetricsService::OnPageLoadStarted() {
643 delegating_provider_.OnPageLoadStarted();
644 }
645
LogCleanShutdown()646 void MetricsService::LogCleanShutdown() {
647 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
648 state_manager_->LogHasSessionShutdownCleanly(true);
649 }
650
ClearSavedStabilityMetrics()651 void MetricsService::ClearSavedStabilityMetrics() {
652 delegating_provider_.ClearSavedStabilityMetrics();
653 // Stability metrics are stored in Local State prefs, so schedule a Local
654 // State write to flush the updated prefs.
655 local_state_->CommitPendingWrite();
656 }
657
MarkCurrentHistogramsAsReported()658 void MetricsService::MarkCurrentHistogramsAsReported() {
659 DiscardingFlattener flattener;
660 base::HistogramSnapshotManager snapshot_manager(&flattener);
661 base::StatisticsRecorder::PrepareDeltas(
662 /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
663 /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
664 &snapshot_manager);
665 }
666
667 #if BUILDFLAG(IS_CHROMEOS_ASH)
SetUserLogStore(std::unique_ptr<UnsentLogStore> user_log_store)668 void MetricsService::SetUserLogStore(
669 std::unique_ptr<UnsentLogStore> user_log_store) {
670 if (log_store()->has_alternate_ongoing_log_store())
671 return;
672
673 if (state_ >= SENDING_LOGS) {
674 // Closes the current log so that a new log can be opened in the user log
675 // store.
676 PushPendingLogsToPersistentStorage(
677 MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreSet);
678 log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
679 OpenNewLog();
680 RecordUserLogStoreState(kSetPostSendLogsState);
681 } else {
682 // Initial log has not yet been created and flushing now would result in
683 // incomplete information in the current log.
684 //
685 // Logs recorded before a user login will be appended to user logs. This
686 // should not happen frequently.
687 //
688 // TODO(crbug/1264627): Look for a way to "pause" pre-login logs and flush
689 // when INIT_TASK is done.
690 log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
691 RecordUserLogStoreState(kSetPreSendLogsState);
692 }
693 }
694
UnsetUserLogStore()695 void MetricsService::UnsetUserLogStore() {
696 if (!log_store()->has_alternate_ongoing_log_store())
697 return;
698
699 if (state_ >= SENDING_LOGS) {
700 PushPendingLogsToPersistentStorage(
701 MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreUnset);
702 log_store()->UnsetAlternateOngoingLogStore();
703 OpenNewLog();
704 RecordUserLogStoreState(kUnsetPostSendLogsState);
705 return;
706 }
707
708 // Fast startup and logout case. We flush all histograms and discard the
709 // current log. This is to prevent histograms captured during the user
710 // session from leaking into local state logs.
711 // TODO(crbug/1381581): Consider not flushing histograms here.
712
713 // Discard histograms.
714 DiscardingFlattener flattener;
715 base::HistogramSnapshotManager histogram_snapshot_manager(&flattener);
716 delegating_provider_.RecordHistogramSnapshots(&histogram_snapshot_manager);
717 base::StatisticsRecorder::PrepareDeltas(
718 /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
719 /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
720 &histogram_snapshot_manager);
721
722 // Discard the current log and don't store it.
723 CHECK(current_log_);
724 current_log_.reset();
725
726 log_store()->UnsetAlternateOngoingLogStore();
727 RecordUserLogStoreState(kUnsetPreSendLogsState);
728 }
729
HasUserLogStore()730 bool MetricsService::HasUserLogStore() {
731 return log_store()->has_alternate_ongoing_log_store();
732 }
733
InitPerUserMetrics()734 void MetricsService::InitPerUserMetrics() {
735 client_->InitPerUserMetrics();
736 }
737
GetCurrentUserMetricsConsent() const738 absl::optional<bool> MetricsService::GetCurrentUserMetricsConsent() const {
739 return client_->GetCurrentUserMetricsConsent();
740 }
741
GetCurrentUserId() const742 absl::optional<std::string> MetricsService::GetCurrentUserId() const {
743 return client_->GetCurrentUserId();
744 }
745
UpdateCurrentUserMetricsConsent(bool user_metrics_consent)746 void MetricsService::UpdateCurrentUserMetricsConsent(
747 bool user_metrics_consent) {
748 client_->UpdateCurrentUserMetricsConsent(user_metrics_consent);
749 }
750 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
751
752 #if BUILDFLAG(IS_CHROMEOS)
ResetClientId()753 void MetricsService::ResetClientId() {
754 // Pref must be cleared in order for ForceClientIdCreation to generate a new
755 // client ID.
756 local_state_->ClearPref(prefs::kMetricsClientID);
757 local_state_->ClearPref(prefs::kMetricsLogRecordId);
758 state_manager_->ForceClientIdCreation();
759 client_->SetMetricsClientId(state_manager_->client_id());
760 }
761 #endif // BUILDFLAG(IS_CHROMEOS)
762
763 variations::SyntheticTrialRegistry*
GetSyntheticTrialRegistry()764 MetricsService::GetSyntheticTrialRegistry() {
765 return client_->GetSyntheticTrialRegistry();
766 }
767
GetInitializationDelay()768 base::TimeDelta MetricsService::GetInitializationDelay() {
769 return base::Seconds(
770 client_->ShouldStartUpFastForTesting() ? 0 : kInitializationDelaySeconds);
771 }
772
GetUpdateLastAliveTimestampDelay()773 base::TimeDelta MetricsService::GetUpdateLastAliveTimestampDelay() {
774 return base::Seconds(kUpdateAliveTimestampSeconds);
775 }
776
StageCurrentLogForTest()777 bool MetricsService::StageCurrentLogForTest() {
778 CloseCurrentLog(/*async=*/false,
779 MetricsLogsEventManager::CreateReason::kUnknown);
780
781 MetricsLogStore* const log_store = reporting_service_.metrics_log_store();
782 log_store->StageNextLog();
783 if (!log_store->has_staged_log())
784 return false;
785
786 OpenNewLog();
787 return true;
788 }
789
790 //------------------------------------------------------------------------------
791 // private methods
792 //------------------------------------------------------------------------------
793
794 //------------------------------------------------------------------------------
795 // Initialization methods
796
InitializeMetricsState()797 void MetricsService::InitializeMetricsState() {
798 SCOPED_UMA_HISTOGRAM_TIMER_MICROS("UMA.MetricsService.Initialize.Time");
799
800 const int64_t buildtime = MetricsLog::GetBuildTime();
801 const std::string version = client_->GetVersionString();
802
803 bool version_changed = false;
804 EnvironmentRecorder recorder(local_state_);
805 int64_t previous_buildtime = recorder.GetLastBuildtime();
806 std::string previous_version = recorder.GetLastVersion();
807 if (previous_buildtime != buildtime || previous_version != version) {
808 recorder.SetBuildtimeAndVersion(buildtime, version);
809 version_changed = true;
810 }
811
812 session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
813
814 StabilityMetricsProvider provider(local_state_);
815 const bool was_last_shutdown_clean = WasLastShutdownClean();
816 if (!was_last_shutdown_clean) {
817 provider.LogCrash(
818 state_manager_->clean_exit_beacon()->browser_last_live_timestamp());
819 #if BUILDFLAG(IS_ANDROID)
820 if (!state_manager_->is_foreground_session()) {
821 // Android can have background sessions in which the app may not come to
822 // the foreground, so signal that Chrome should stop watching for crashes
823 // here. This ensures that the termination of such sessions is not
824 // considered a crash. If and when the app enters the foreground, Chrome
825 // starts watching for crashes via MetricsService::OnAppEnterForeground().
826 //
827 // TODO(crbug/1232027): Such sessions do not yet exist on iOS. When they
828 // do, it may not be possible to know at this point whether a session is a
829 // background session.
830 //
831 // TODO(crbug/1245347): On WebLayer, it is not possible to know whether
832 // it's a background session at this point.
833 //
834 // TODO(crbug/1245676): Ditto for WebView.
835 state_manager_->clean_exit_beacon()->WriteBeaconValue(true);
836 }
837 #endif // BUILDFLAG(IS_ANDROID)
838 }
839
840 // HasPreviousSessionData is called first to ensure it is never bypassed.
841 const bool is_initial_stability_log_required =
842 delegating_provider_.HasPreviousSessionData() || !was_last_shutdown_clean;
843 bool has_initial_stability_log = false;
844 if (is_initial_stability_log_required) {
845 // If the previous session didn't exit cleanly, or if any provider
846 // explicitly requests it, prepare an initial stability log -
847 // provided UMA is enabled.
848 if (state_manager_->IsMetricsReportingEnabled()) {
849 has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
850 }
851 }
852
853 // If the version changed, but no initial stability log was generated, clear
854 // the stability stats from the previous version (so that they don't get
855 // attributed to the current version). This could otherwise happen due to a
856 // number of different edge cases, such as if the last version crashed before
857 // it could save off a system profile or if UMA reporting is disabled (which
858 // normally results in stats being accumulated).
859 if (version_changed && !has_initial_stability_log)
860 ClearSavedStabilityMetrics();
861
862 // If the version changed, the system profile is obsolete and needs to be
863 // cleared. This is to avoid the stability data misattribution that could
864 // occur if the current version crashed before saving its own system profile.
865 // Note however this clearing occurs only after preparing the initial
866 // stability log, an operation that requires the previous version's system
867 // profile. At this point, stability metrics pertaining to the previous
868 // version have been cleared.
869 if (version_changed)
870 recorder.ClearEnvironmentFromPrefs();
871
872 // Update session ID.
873 ++session_id_;
874 local_state_->SetInteger(prefs::kMetricsSessionID, session_id_);
875
876 // Notify stability metrics providers about the launch.
877 provider.LogLaunch();
878
879 // Call GetUptimes() for the first time, thus allowing all later calls
880 // to record incremental uptimes accurately.
881 base::TimeDelta ignored_uptime_parameter;
882 base::TimeDelta startup_uptime;
883 GetUptimes(local_state_, &startup_uptime, &ignored_uptime_parameter);
884 DCHECK_EQ(0, startup_uptime.InMicroseconds());
885 }
886
OnUserAction(const std::string & action,base::TimeTicks action_time)887 void MetricsService::OnUserAction(const std::string& action,
888 base::TimeTicks action_time) {
889 current_log_->RecordUserAction(action, action_time);
890 HandleIdleSinceLastTransmission(false);
891 }
892
FinishedInitTask()893 void MetricsService::FinishedInitTask() {
894 DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
895 state_ = INIT_TASK_DONE;
896 rotation_scheduler_->InitTaskComplete();
897 }
898
GetUptimes(PrefService * pref,base::TimeDelta * incremental_uptime,base::TimeDelta * uptime)899 void MetricsService::GetUptimes(PrefService* pref,
900 base::TimeDelta* incremental_uptime,
901 base::TimeDelta* uptime) {
902 base::TimeTicks now = base::TimeTicks::Now();
903 // If this is the first call, init |first_updated_time_| and
904 // |last_updated_time_|.
905 if (last_updated_time_.is_null()) {
906 first_updated_time_ = now;
907 last_updated_time_ = now;
908 }
909 *incremental_uptime = now - last_updated_time_;
910 *uptime = now - first_updated_time_;
911 last_updated_time_ = now;
912 }
913
914 //------------------------------------------------------------------------------
915 // Recording control methods
916
OpenNewLog(bool call_providers)917 void MetricsService::OpenNewLog(bool call_providers) {
918 CHECK(!current_log_);
919
920 current_log_ = CreateLog(MetricsLog::ONGOING_LOG);
921 if (call_providers) {
922 delegating_provider_.OnDidCreateMetricsLog();
923 }
924
925 DCHECK_NE(CONSTRUCTED, state_);
926 if (state_ == INITIALIZED) {
927 // We only need to schedule that run once.
928 state_ = INIT_TASK_SCHEDULED;
929
930 base::TimeDelta initialization_delay = GetInitializationDelay();
931 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
932 FROM_HERE,
933 base::BindOnce(&MetricsService::StartInitTask,
934 self_ptr_factory_.GetWeakPtr()),
935 initialization_delay);
936
937 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
938 FROM_HERE,
939 base::BindOnce(&MetricsService::PrepareProviderMetricsTask,
940 self_ptr_factory_.GetWeakPtr()),
941 2 * initialization_delay);
942 }
943 }
944
945 MetricsService::FinalizedLog::FinalizedLog() = default;
946 MetricsService::FinalizedLog::~FinalizedLog() = default;
947 MetricsService::FinalizedLog::FinalizedLog(FinalizedLog&& other) = default;
948 MetricsService::FinalizedLog& MetricsService::FinalizedLog::operator=(
949 FinalizedLog&& other) = default;
950
MetricsLogHistogramWriter(MetricsLog * log)951 MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
952 MetricsLog* log)
953 : MetricsLogHistogramWriter(log,
954 base::Histogram::kUmaTargetedHistogramFlag) {}
955
MetricsLogHistogramWriter(MetricsLog * log,base::HistogramBase::Flags required_flags)956 MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
957 MetricsLog* log,
958 base::HistogramBase::Flags required_flags)
959 : required_flags_(required_flags),
960 flattener_(std::make_unique<IndependentFlattener>(log)),
961 histogram_snapshot_manager_(
962 std::make_unique<base::HistogramSnapshotManager>(flattener_.get())),
963 snapshot_transaction_id_(0) {}
964
965 MetricsService::MetricsLogHistogramWriter::~MetricsLogHistogramWriter() =
966 default;
967
968 void MetricsService::MetricsLogHistogramWriter::
SnapshotStatisticsRecorderDeltas()969 SnapshotStatisticsRecorderDeltas() {
970 SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.SnapshotDeltasTime");
971 snapshot_transaction_id_ = base::StatisticsRecorder::PrepareDeltas(
972 /*include_persistent=*/true,
973 /*flags_to_set=*/base::Histogram::kNoFlags, required_flags_,
974 histogram_snapshot_manager_.get());
975 }
976
977 void MetricsService::MetricsLogHistogramWriter::
SnapshotStatisticsRecorderUnloggedSamples()978 SnapshotStatisticsRecorderUnloggedSamples() {
979 snapshot_transaction_id_ = base::StatisticsRecorder::SnapshotUnloggedSamples(
980 required_flags_, histogram_snapshot_manager_.get());
981 }
982
IndependentMetricsLoader(std::unique_ptr<MetricsLog> log,std::string app_version,std::string signing_key)983 MetricsService::IndependentMetricsLoader::IndependentMetricsLoader(
984 std::unique_ptr<MetricsLog> log,
985 std::string app_version,
986 std::string signing_key)
987 : log_(std::move(log)),
988 flattener_(new IndependentFlattener(log_.get())),
989 snapshot_manager_(new base::HistogramSnapshotManager(flattener_.get())),
990 app_version_(std::move(app_version)),
991 signing_key_(std::move(signing_key)) {
992 CHECK(log_);
993 CHECK_EQ(log_->log_type(), MetricsLog::INDEPENDENT_LOG);
994 }
995
996 MetricsService::IndependentMetricsLoader::~IndependentMetricsLoader() = default;
997
Run(base::OnceCallback<void (bool)> done_callback,MetricsProvider * metrics_provider)998 void MetricsService::IndependentMetricsLoader::Run(
999 base::OnceCallback<void(bool)> done_callback,
1000 MetricsProvider* metrics_provider) {
1001 CHECK(!run_called_);
1002 run_called_ = true;
1003
1004 metrics_provider->ProvideIndependentMetrics(
1005 // Unretained is safe because this callback is either called before
1006 // |done_callback|, or in |done_callback|. Either case is fine because
1007 // |done_callback| owns |this|.
1008 base::BindOnce(&MetricsService::IndependentMetricsLoader::FinalizeLog,
1009 base::Unretained(this)),
1010 std::move(done_callback), log_->uma_proto(), snapshot_manager_.get());
1011 }
1012
FinalizeLog()1013 void MetricsService::IndependentMetricsLoader::FinalizeLog() {
1014 CHECK(run_called_);
1015 CHECK(!finalize_log_called_);
1016 finalize_log_called_ = true;
1017
1018 // Release |snapshot_manager_| and then |flattener_| to prevent dangling
1019 // pointers, since |log_| will be released in MetricsService::FinalizeLog().
1020 snapshot_manager_.reset();
1021 flattener_.reset();
1022
1023 // Note that the close_time param must not be set for independent logs.
1024 finalized_log_ = MetricsService::FinalizeLog(
1025 std::move(log_), /*truncate_events=*/false, /*close_time=*/absl::nullopt,
1026 app_version_, signing_key_);
1027 }
1028
HasFinalizedLog()1029 bool MetricsService::IndependentMetricsLoader::HasFinalizedLog() {
1030 return finalize_log_called_ && !release_finalized_log_called_;
1031 }
1032
1033 MetricsService::FinalizedLog
ReleaseFinalizedLog()1034 MetricsService::IndependentMetricsLoader::ReleaseFinalizedLog() {
1035 CHECK(HasFinalizedLog());
1036
1037 release_finalized_log_called_ = true;
1038 return std::move(finalized_log_);
1039 }
1040
StartInitTask()1041 void MetricsService::StartInitTask() {
1042 delegating_provider_.AsyncInit(base::BindOnce(
1043 &MetricsService::FinishedInitTask, self_ptr_factory_.GetWeakPtr()));
1044 }
1045
CloseCurrentLog(bool async,MetricsLogsEventManager::CreateReason reason,base::OnceClosure log_stored_callback)1046 void MetricsService::CloseCurrentLog(
1047 bool async,
1048 MetricsLogsEventManager::CreateReason reason,
1049 base::OnceClosure log_stored_callback) {
1050 if (!current_log_) {
1051 return;
1052 }
1053
1054 // If a persistent allocator is in use, update its internal histograms (such
1055 // as how much memory is being used) before reporting.
1056 base::PersistentHistogramAllocator* allocator =
1057 base::GlobalHistogramAllocator::Get();
1058 if (allocator)
1059 allocator->UpdateTrackingHistograms();
1060
1061 // Put incremental data (histogram deltas, and realtime stats deltas) at the
1062 // end of all log transmissions (initial log handles this separately).
1063 // RecordIncrementalStabilityElements only exists on the derived
1064 // MetricsLog class.
1065 std::unique_ptr<MetricsLog> current_log(std::move(current_log_));
1066 RecordCurrentEnvironment(current_log.get(), /*complete=*/true);
1067 base::TimeDelta incremental_uptime;
1068 base::TimeDelta uptime;
1069 GetUptimes(local_state_, &incremental_uptime, &uptime);
1070 current_log->RecordCurrentSessionData(incremental_uptime, uptime,
1071 &delegating_provider_, local_state_);
1072
1073 auto log_histogram_writer =
1074 std::make_unique<MetricsLogHistogramWriter>(current_log.get());
1075
1076 // Let metrics providers provide histogram snapshots independently if they
1077 // have any. This is done synchronously.
1078 delegating_provider_.RecordHistogramSnapshots(
1079 log_histogram_writer->histogram_snapshot_manager());
1080
1081 MetricsLog::LogType log_type = current_log->log_type();
1082 CHECK_EQ(log_type, MetricsLog::ONGOING_LOG);
1083 ChromeUserMetricsExtension::RealLocalTime close_time =
1084 current_log->GetCurrentClockTime(/*record_time_zone=*/true);
1085 std::string signing_key = log_store()->GetSigningKeyForLogType(log_type);
1086 std::string current_app_version = client_->GetVersionString();
1087
1088 #if !BUILDFLAG(IS_ANDROID)
1089 if (base::FeatureList::IsEnabled(
1090 features::kMetricsServiceDeltaSnapshotInBg)) {
1091 // If this is an async periodic log, and the browser is about to be shut
1092 // down (determined by KeepAliveRegistry::IsShuttingDown(), indicating that
1093 // there is nothing else to keep the browser alive), then do the work
1094 // synchronously instead. Otherwise, creating a ScopedKeepAlive below while
1095 // the KeepAliveRegistry has already started shutting down will trigger a
1096 // CHECK. Alternatively, the ScopedKeepAlive below could be omitted when the
1097 // KeepAliveRegistry is shutting down, but since the browser is shutting
1098 // down soon, then it is likely that the asynchronous task to close the
1099 // current the log will be cut short, causing data loss.
1100 if (async && KeepAliveRegistry::GetInstance()->IsShuttingDown()) {
1101 async = false;
1102 }
1103 }
1104 #endif
1105
1106 if (async) {
1107 if (base::FeatureList::IsEnabled(
1108 features::kMetricsServiceDeltaSnapshotInBg)) {
1109 // In this mode, we perform the full "delta snapshot" (snapshotting
1110 // unlogged samples and marking them as logged) in the background, in
1111 // contrast to snapshotting unlogged samples in the background and marking
1112 // them as logged when back on the main thread, as is done in the else
1113 // branch.
1114
1115 auto background_task = base::BindOnce(
1116 &MetricsService::SnapshotDeltasAndFinalizeLog,
1117 std::move(log_histogram_writer), std::move(current_log),
1118 /*truncate_events=*/true, std::move(close_time),
1119 std::move(current_app_version), std::move(signing_key));
1120 auto reply_task = base::BindOnce(&MetricsService::StoreFinalizedLog,
1121 self_ptr_factory_.GetWeakPtr(), log_type,
1122 reason, std::move(log_stored_callback));
1123
1124 #if !BUILDFLAG(IS_ANDROID)
1125 // Prevent the browser from shutting down while creating the log in the
1126 // background. This is done by creating a ScopedKeepAlive that is only
1127 // destroyed after the log has been stored. Not used on Android because it
1128 // has no shutdown code path.
1129 reply_task = std::move(reply_task)
1130 .Then(base::BindOnce(
1131 [](std::unique_ptr<ScopedKeepAlive>) {
1132 // This function does nothing but keep the
1133 // ScopedKeepAlive param alive until we have
1134 // finished storing the log.
1135 },
1136 std::make_unique<ScopedKeepAlive>(
1137 KeepAliveOrigin::UMA_LOG,
1138 KeepAliveRestartOption::DISABLED)));
1139 #endif // !BUILDFLAG(IS_ANDROID)
1140
1141 base::ThreadPool::PostTaskAndReplyWithResult(
1142 FROM_HERE,
1143 {base::TaskPriority::USER_BLOCKING,
1144 base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
1145 std::move(background_task), std::move(reply_task));
1146 } else {
1147 // To finalize the log asynchronously, we snapshot the unlogged samples of
1148 // histograms and fill them into the log, without actually marking the
1149 // samples as logged. We only mark them as logged after running the main
1150 // thread reply task to store the log. This way, we will not lose the
1151 // samples in case Chrome closes while the background task is running.
1152 // Note that while this async log is being finalized, it is possible that
1153 // another log is finalized and stored synchronously, which could
1154 // potentially cause the same samples to be in two different logs, and
1155 // hence sent twice. To prevent this, if a synchronous log is stored while
1156 // the async one is being finalized, we discard the async log as it would
1157 // be a subset of the synchronous one (in terms of histograms). For more
1158 // details, see MaybeCleanUpAndStoreFinalizedLog().
1159 //
1160 // TODO(crbug/1052796): Find a way to save the other data such as user
1161 // actions and omnibox events when we discard an async log.
1162 MetricsLogHistogramWriter* log_histogram_writer_ptr =
1163 log_histogram_writer.get();
1164 base::ThreadPool::PostTaskAndReplyWithResult(
1165 FROM_HERE,
1166 // CONTINUE_ON_SHUTDOWN because the work done is only useful once the
1167 // reply task is run (and there are no side effects). So, no need to
1168 // block shutdown since the reply task won't be run anyway.
1169 // NOTE: If attempting to change the USER_BLOCKING priority, do a
1170 // study on the impact first since it might affect the number of logs
1171 // being uploaded (which might have secondary effects, e.g. on metrics
1172 // that rely on number of logs uploaded).
1173 {base::TaskPriority::USER_BLOCKING,
1174 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
1175 base::BindOnce(&MetricsService::SnapshotUnloggedSamplesAndFinalizeLog,
1176 log_histogram_writer_ptr, std::move(current_log),
1177 /*truncate_events=*/true, std::move(close_time),
1178 std::move(current_app_version),
1179 std::move(signing_key)),
1180 base::BindOnce(&MetricsService::MaybeCleanUpAndStoreFinalizedLog,
1181 self_ptr_factory_.GetWeakPtr(),
1182 std::move(log_histogram_writer), log_type, reason,
1183 std::move(log_stored_callback)));
1184 async_ongoing_log_posted_time_ = base::TimeTicks::Now();
1185 }
1186 } else {
1187 FinalizedLog finalized_log = SnapshotDeltasAndFinalizeLog(
1188 std::move(log_histogram_writer), std::move(current_log),
1189 /*truncate_events=*/true, std::move(close_time),
1190 std::move(current_app_version), std::move(signing_key));
1191 StoreFinalizedLog(log_type, reason, std::move(log_stored_callback),
1192 std::move(finalized_log));
1193 }
1194 }
1195
StoreFinalizedLog(MetricsLog::LogType log_type,MetricsLogsEventManager::CreateReason reason,base::OnceClosure done_callback,FinalizedLog finalized_log)1196 void MetricsService::StoreFinalizedLog(
1197 MetricsLog::LogType log_type,
1198 MetricsLogsEventManager::CreateReason reason,
1199 base::OnceClosure done_callback,
1200 FinalizedLog finalized_log) {
1201 log_store()->StoreLogInfo(std::move(finalized_log.log_info),
1202 finalized_log.uncompressed_log_size, log_type,
1203 reason);
1204 std::move(done_callback).Run();
1205 }
1206
MaybeCleanUpAndStoreFinalizedLog(std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,MetricsLog::LogType log_type,MetricsLogsEventManager::CreateReason reason,base::OnceClosure done_callback,FinalizedLog finalized_log)1207 void MetricsService::MaybeCleanUpAndStoreFinalizedLog(
1208 std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,
1209 MetricsLog::LogType log_type,
1210 MetricsLogsEventManager::CreateReason reason,
1211 base::OnceClosure done_callback,
1212 FinalizedLog finalized_log) {
1213 UMA_HISTOGRAM_TIMES("UMA.MetricsService.PeriodicOngoingLog.ReplyTime",
1214 base::TimeTicks::Now() - async_ongoing_log_posted_time_);
1215
1216 // Store the finalized log only if the StatisticRecorder's last transaction ID
1217 // is the same as the one from |log_histogram_writer|. If they are not the
1218 // same, then it indicates that another log was created while creating
1219 // |finalized_log| (that log would be a superset of |finalized_log| in terms
1220 // of histograms, so we discard |finalized_log| by not storing it).
1221 //
1222 // TODO(crbug/1052796): Find a way to save the other data such as user actions
1223 // and omnibox events when we discard |finalized_log|.
1224 //
1225 // Note that the call to StatisticsRecorder::GetLastSnapshotTransactionId()
1226 // here should not have to wait for a lock since there should not be any async
1227 // logs being created (|rotation_scheduler_| is only re-scheduled at the end
1228 // of this method).
1229 bool should_store_log =
1230 (base::StatisticsRecorder::GetLastSnapshotTransactionId() ==
1231 log_histogram_writer->snapshot_transaction_id());
1232 base::UmaHistogramBoolean("UMA.MetricsService.ShouldStoreAsyncLog",
1233 should_store_log);
1234
1235 if (!should_store_log) {
1236 // We still need to run |done_callback| even if we do not store the log.
1237 std::move(done_callback).Run();
1238 return;
1239 }
1240
1241 SCOPED_UMA_HISTOGRAM_TIMER(
1242 "UMA.MetricsService.MaybeCleanUpAndStoreFinalizedLog.Time");
1243
1244 log_histogram_writer->histogram_snapshot_manager()
1245 ->MarkUnloggedSamplesAsLogged();
1246 StoreFinalizedLog(log_type, reason, std::move(done_callback),
1247 std::move(finalized_log));
1248 }
1249
PushPendingLogsToPersistentStorage(MetricsLogsEventManager::CreateReason reason)1250 void MetricsService::PushPendingLogsToPersistentStorage(
1251 MetricsLogsEventManager::CreateReason reason) {
1252 if (IsTooEarlyToCloseLog()) {
1253 return;
1254 }
1255
1256 base::UmaHistogramBoolean("UMA.MetricsService.PendingOngoingLog",
1257 pending_ongoing_log_);
1258
1259 // Close and store a log synchronously because this is usually called in
1260 // critical code paths (e.g., shutdown) where we may not have time to run
1261 // background tasks.
1262 CloseCurrentLog(/*async=*/false, reason);
1263 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
1264 }
1265
1266 //------------------------------------------------------------------------------
1267 // Transmission of logs methods
1268
StartSchedulerIfNecessary()1269 void MetricsService::StartSchedulerIfNecessary() {
1270 // Never schedule cutting or uploading of logs in test mode.
1271 if (test_mode_active_)
1272 return;
1273
1274 // Even if reporting is disabled, the scheduler is needed to trigger the
1275 // creation of the first ongoing log, which must be done in order for any logs
1276 // to be persisted on shutdown or backgrounding.
1277 if (recording_active() && (reporting_active() || state_ < SENDING_LOGS)) {
1278 rotation_scheduler_->Start();
1279 reporting_service_.Start();
1280 }
1281 }
1282
StartScheduledUpload()1283 void MetricsService::StartScheduledUpload() {
1284 DVLOG(1) << "StartScheduledUpload";
1285 DCHECK(state_ >= INIT_TASK_DONE);
1286
1287 // If we're getting no notifications, then the log won't have much in it, and
1288 // it's possible the computer is about to go to sleep, so don't upload and
1289 // stop the scheduler.
1290 // If recording has been turned off, the scheduler doesn't need to run.
1291 // If reporting is off, proceed if the first ongoing log hasn't been created,
1292 // since that has to happen in order for logs to be cut and stored when
1293 // persisting.
1294 // TODO(stuartmorgan): Call Stop() on the scheduler when reporting and/or
1295 // recording are turned off instead of letting it fire and then aborting.
1296 if (idle_since_last_transmission_ || !recording_active() ||
1297 (!reporting_active() && state_ >= SENDING_LOGS)) {
1298 rotation_scheduler_->Stop();
1299 rotation_scheduler_->RotationFinished();
1300 return;
1301 }
1302
1303 // The first ongoing log should be collected prior to sending any unsent logs.
1304 if (state_ == INIT_TASK_DONE) {
1305 client_->CollectFinalMetricsForLog(
1306 base::BindOnce(&MetricsService::OnFinalLogInfoCollectionDone,
1307 self_ptr_factory_.GetWeakPtr()));
1308 return;
1309 }
1310
1311 // If there are unsent logs, send the next one. If not, start the asynchronous
1312 // process of finalizing the current log for upload.
1313 if (has_unsent_logs()) {
1314 reporting_service_.Start();
1315 rotation_scheduler_->RotationFinished();
1316 } else {
1317 // There are no logs left to send, so start creating a new one.
1318 client_->CollectFinalMetricsForLog(
1319 base::BindOnce(&MetricsService::OnFinalLogInfoCollectionDone,
1320 self_ptr_factory_.GetWeakPtr()));
1321 }
1322 }
1323
OnFinalLogInfoCollectionDone()1324 void MetricsService::OnFinalLogInfoCollectionDone() {
1325 DVLOG(1) << "OnFinalLogInfoCollectionDone";
1326 DCHECK(state_ >= INIT_TASK_DONE);
1327 state_ = SENDING_LOGS;
1328
1329 // Abort if metrics were turned off during the final info gathering.
1330 if (!recording_active()) {
1331 rotation_scheduler_->Stop();
1332 rotation_scheduler_->RotationFinished();
1333 return;
1334 }
1335
1336 SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.PeriodicOngoingLog.CloseTime");
1337
1338 // There shouldn't be two periodic ongoing logs being finalized in the
1339 // background simultaneously. This is currently enforced because:
1340 // 1. Only periodic ongoing logs are finalized asynchronously (i.e., logs
1341 // created by the MetricsRotationScheduler).
1342 // 2. We only re-schedule the MetricsRotationScheduler after storing a
1343 // periodic ongoing log.
1344 //
1345 // TODO(crbug/1052796): Consider making it possible to have multiple
1346 // simultaneous async logs by having some queueing system (e.g., if we want
1347 // the log created when foregrounding Chrome to be async).
1348 DCHECK(!pending_ongoing_log_);
1349 pending_ongoing_log_ = true;
1350
1351 base::OnceClosure log_stored_callback =
1352 base::BindOnce(&MetricsService::OnAsyncPeriodicOngoingLogStored,
1353 self_ptr_factory_.GetWeakPtr());
1354 CloseCurrentLog(/*async=*/true,
1355 MetricsLogsEventManager::CreateReason::kPeriodic,
1356 std::move(log_stored_callback));
1357 OpenNewLog(/*call_providers=*/false);
1358 }
1359
OnAsyncPeriodicOngoingLogStored()1360 void MetricsService::OnAsyncPeriodicOngoingLogStored() {
1361 pending_ongoing_log_ = false;
1362
1363 // Call OnDidCreateMetricsLog() after storing a log instead of directly after
1364 // opening a log. Otherwise, the async log that was created would potentially
1365 // have mistakenly snapshotted the histograms intended for the newly opened
1366 // log.
1367 delegating_provider_.OnDidCreateMetricsLog();
1368
1369 // Trim and store unsent logs, including the log that was just closed, so that
1370 // they're not lost in case of a crash before upload time. However, the
1371 // in-memory log store is unchanged. I.e., logs that are trimmed will still be
1372 // available in memory. This is to give the log that was just created a chance
1373 // to be sent in case it is trimmed. After uploading (whether successful or
1374 // not), the log store is trimmed and stored again, and at that time, the
1375 // in-memory log store will be updated.
1376 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/false);
1377
1378 // Do not re-schedule if metrics were turned off while finalizing the log.
1379 if (!recording_active()) {
1380 rotation_scheduler_->Stop();
1381 rotation_scheduler_->RotationFinished();
1382 } else {
1383 // Only re-schedule |rotation_scheduler_| *after* the log was stored to
1384 // ensure that only one log is created asynchronously at a time.
1385 reporting_service_.Start();
1386 rotation_scheduler_->RotationFinished();
1387 HandleIdleSinceLastTransmission(true);
1388 }
1389 }
1390
PrepareInitialStabilityLog(const std::string & prefs_previous_version)1391 bool MetricsService::PrepareInitialStabilityLog(
1392 const std::string& prefs_previous_version) {
1393 DCHECK_EQ(CONSTRUCTED, state_);
1394
1395 MetricsLog::LogType log_type = MetricsLog::INITIAL_STABILITY_LOG;
1396 std::unique_ptr<MetricsLog> initial_stability_log(CreateLog(log_type));
1397
1398 // Do not call OnDidCreateMetricsLog here because the stability log describes
1399 // stats from the _previous_ session.
1400
1401 if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(local_state_))
1402 return false;
1403
1404 initial_stability_log->RecordPreviousSessionData(&delegating_provider_,
1405 local_state_);
1406
1407 auto log_histogram_writer = std::make_unique<MetricsLogHistogramWriter>(
1408 initial_stability_log.get(), base::Histogram::kUmaStabilityHistogramFlag);
1409
1410 // Add a beacon to this record to indicate that it's part of the initial
1411 // stability log.
1412 UMA_STABILITY_HISTOGRAM_BOOLEAN("UMA.InitialStabilityRecordBeacon", true);
1413
1414 // Let metrics providers provide histogram snapshots independently if they
1415 // have any. This is done synchronously.
1416 delegating_provider_.RecordInitialHistogramSnapshots(
1417 log_histogram_writer->histogram_snapshot_manager());
1418
1419 std::string signing_key = log_store()->GetSigningKeyForLogType(log_type);
1420
1421 // Synchronously create the initial stability log in order to ensure that the
1422 // stability histograms are filled into this specific log. Note that the
1423 // close_time param must not be set for initial stability logs.
1424 FinalizedLog finalized_log = SnapshotDeltasAndFinalizeLog(
1425 std::move(log_histogram_writer), std::move(initial_stability_log),
1426 /*truncate_events=*/false, /*close_time=*/absl::nullopt,
1427 client_->GetVersionString(), std::move(signing_key));
1428 StoreFinalizedLog(log_type, MetricsLogsEventManager::CreateReason::kStability,
1429 base::DoNothing(), std::move(finalized_log));
1430
1431 // Store unsent logs, including the stability log that was just saved, so
1432 // that they're not lost in case of a crash before upload time.
1433 log_store()->TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
1434
1435 return true;
1436 }
1437
RegisterMetricsProvider(std::unique_ptr<MetricsProvider> provider)1438 void MetricsService::RegisterMetricsProvider(
1439 std::unique_ptr<MetricsProvider> provider) {
1440 DCHECK_EQ(CONSTRUCTED, state_);
1441 delegating_provider_.RegisterMetricsProvider(std::move(provider));
1442 }
1443
CheckForClonedInstall()1444 void MetricsService::CheckForClonedInstall() {
1445 state_manager_->CheckForClonedInstall();
1446 }
1447
ShouldResetClientIdsOnClonedInstall()1448 bool MetricsService::ShouldResetClientIdsOnClonedInstall() {
1449 return state_manager_->ShouldResetClientIdsOnClonedInstall();
1450 }
1451
CreateLog(MetricsLog::LogType log_type)1452 std::unique_ptr<MetricsLog> MetricsService::CreateLog(
1453 MetricsLog::LogType log_type) {
1454 auto new_metrics_log = std::make_unique<MetricsLog>(
1455 state_manager_->client_id(), session_id_, log_type, client_);
1456 new_metrics_log->AssignRecordId(local_state_);
1457
1458 #if BUILDFLAG(IS_CHROMEOS_ASH)
1459 absl::optional<std::string> user_id = GetCurrentUserId();
1460 if (user_id.has_value())
1461 new_metrics_log->SetUserId(user_id.value());
1462 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
1463
1464 return new_metrics_log;
1465 }
1466
AddLogsObserver(MetricsLogsEventManager::Observer * observer)1467 void MetricsService::AddLogsObserver(
1468 MetricsLogsEventManager::Observer* observer) {
1469 logs_event_manager_.AddObserver(observer);
1470 }
1471
RemoveLogsObserver(MetricsLogsEventManager::Observer * observer)1472 void MetricsService::RemoveLogsObserver(
1473 MetricsLogsEventManager::Observer* observer) {
1474 logs_event_manager_.RemoveObserver(observer);
1475 }
1476
AddEnablementObserver(const base::RepeatingCallback<void (bool)> & observer)1477 base::CallbackListSubscription MetricsService::AddEnablementObserver(
1478 const base::RepeatingCallback<void(bool)>& observer) {
1479 return enablement_observers_.Add(observer);
1480 }
1481
SetPersistentSystemProfile(const std::string & serialized_proto,bool complete)1482 void MetricsService::SetPersistentSystemProfile(
1483 const std::string& serialized_proto,
1484 bool complete) {
1485 GlobalPersistentSystemProfile::GetInstance()->SetSystemProfile(
1486 serialized_proto, complete);
1487 }
1488
1489 // static
RecordCurrentEnvironmentHelper(MetricsLog * log,PrefService * local_state,DelegatingProvider * delegating_provider)1490 std::string MetricsService::RecordCurrentEnvironmentHelper(
1491 MetricsLog* log,
1492 PrefService* local_state,
1493 DelegatingProvider* delegating_provider) {
1494 const SystemProfileProto& system_profile =
1495 log->RecordEnvironment(delegating_provider);
1496 EnvironmentRecorder recorder(local_state);
1497 return recorder.SerializeAndRecordEnvironmentToPrefs(system_profile);
1498 }
1499
RecordCurrentEnvironment(MetricsLog * log,bool complete)1500 void MetricsService::RecordCurrentEnvironment(MetricsLog* log, bool complete) {
1501 DCHECK(client_);
1502 std::string serialized_proto =
1503 RecordCurrentEnvironmentHelper(log, local_state_, &delegating_provider_);
1504
1505 SetPersistentSystemProfile(serialized_proto, complete);
1506 client_->OnEnvironmentUpdate(&serialized_proto);
1507
1508 // The call to SetPersistentSystemProfile() above will have written the
1509 // current system profile to persistent memory. Because it may span over
1510 // multiple pages, it is possible that the system profile may become corrupted
1511 // if only certain pages were flushed to disk. For example, say we overwrite
1512 // the persistent memory's system profile with a newer one, and that it spans
1513 // over two pages. Then, the OS flushes the second page, but not the first
1514 // page. If the device is shut down unexpectedly, e.g. due to a power outage,
1515 // then the first page will contain the beginning of the old system profile,
1516 // while the second page will contain the ending of the new system profile,
1517 // resulting in an unparsable system profile and rendering the whole file
1518 // useless. So, manually schedule a flush every time we overwrite the system
1519 // profile with a new one to ensure we don't ever get a corrupted one.
1520 if (base::FeatureList::IsEnabled(
1521 features::kFlushPersistentSystemProfileOnWrite)) {
1522 base::ThreadPool::PostTask(
1523 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
1524 base::BindOnce([]() {
1525 if (auto* allocator = base::GlobalHistogramAllocator::Get()) {
1526 // Ideally, we'd just call Flush() with the |sync| parameter set to
1527 // false on the main thread, but Windows does not support async
1528 // flushing, so do this synchronously on a background thread
1529 // instead.
1530 allocator->memory_allocator()->Flush(/*sync=*/true);
1531 }
1532 }));
1533 }
1534 }
1535
PrepareProviderMetricsLogDone(std::unique_ptr<IndependentMetricsLoader> loader,bool success)1536 void MetricsService::PrepareProviderMetricsLogDone(
1537 std::unique_ptr<IndependentMetricsLoader> loader,
1538 bool success) {
1539 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1540 DCHECK(independent_loader_active_);
1541 DCHECK(loader);
1542
1543 if (success) {
1544 // If not already done, finalize the log that was created independently by
1545 // the metrics provider.
1546 if (!loader->HasFinalizedLog()) {
1547 loader->FinalizeLog();
1548 }
1549
1550 StoreFinalizedLog(MetricsLog::INDEPENDENT_LOG,
1551 MetricsLogsEventManager::CreateReason::kIndependent,
1552 /*done_callback=*/base::DoNothing(),
1553 loader->ReleaseFinalizedLog());
1554 }
1555
1556 independent_loader_active_ = false;
1557 }
1558
PrepareProviderMetricsLog()1559 bool MetricsService::PrepareProviderMetricsLog() {
1560 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1561
1562 // If something is still pending, stop now and indicate that there is
1563 // still work to do.
1564 if (independent_loader_active_)
1565 return true;
1566
1567 // Check each provider in turn for data.
1568 for (auto& provider : delegating_provider_.GetProviders()) {
1569 if (provider->HasIndependentMetrics()) {
1570 // Create a new log. This will have some default values injected in it
1571 // but those will be overwritten when an embedded profile is extracted.
1572 std::unique_ptr<MetricsLog> log = CreateLog(MetricsLog::INDEPENDENT_LOG);
1573
1574 // Note that something is happening. This must be set before the
1575 // operation is requested in case the loader decides to do everything
1576 // immediately rather than as a background task.
1577 independent_loader_active_ = true;
1578
1579 // Give the new log to a loader for management and then run it on the
1580 // provider that has something to give. A copy of the pointer is needed
1581 // because the unique_ptr may get moved before the value can be used
1582 // to call Run().
1583 std::unique_ptr<IndependentMetricsLoader> loader =
1584 std::make_unique<IndependentMetricsLoader>(
1585 std::move(log), client_->GetVersionString(),
1586 log_store()->GetSigningKeyForLogType(
1587 MetricsLog::INDEPENDENT_LOG));
1588 IndependentMetricsLoader* loader_ptr = loader.get();
1589 loader_ptr->Run(
1590 base::BindOnce(&MetricsService::PrepareProviderMetricsLogDone,
1591 self_ptr_factory_.GetWeakPtr(), std::move(loader)),
1592 provider.get());
1593
1594 // Something was found so there may still be more work to do.
1595 return true;
1596 }
1597 }
1598
1599 // Nothing was found so indicate there is no more work to do.
1600 return false;
1601 }
1602
PrepareProviderMetricsTask()1603 void MetricsService::PrepareProviderMetricsTask() {
1604 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1605 bool found = PrepareProviderMetricsLog();
1606 base::TimeDelta next_check = found ? base::Seconds(5) : base::Minutes(15);
1607 base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
1608 FROM_HERE,
1609 base::BindOnce(&MetricsService::PrepareProviderMetricsTask,
1610 self_ptr_factory_.GetWeakPtr()),
1611 next_check);
1612 }
1613
UpdateLastLiveTimestampTask()1614 void MetricsService::UpdateLastLiveTimestampTask() {
1615 state_manager_->clean_exit_beacon()->UpdateLastLiveTimestamp();
1616
1617 // Schecule the next update.
1618 StartUpdatingLastLiveTimestamp();
1619 }
1620
IsTooEarlyToCloseLog()1621 bool MetricsService::IsTooEarlyToCloseLog() {
1622 // When kMetricsServiceAllowEarlyLogClose is enabled, start closing logs as
1623 // soon as the first log is opened (|state_| is set to INIT_TASK_SCHEDULED
1624 // when the first log is opened, see OpenNewLog()). Otherwise, only start
1625 // closing logs when logs have started being sent.
1626 return base::FeatureList::IsEnabled(
1627 features::kMetricsServiceAllowEarlyLogClose)
1628 ? state_ < INIT_TASK_SCHEDULED
1629 : state_ < SENDING_LOGS;
1630 }
1631
OnClonedInstallDetected()1632 void MetricsService::OnClonedInstallDetected() {
1633 // Purge all logs, as they may come from a previous install. Unfortunately,
1634 // since the cloned install detector works asynchronously, it is possible that
1635 // this is called after logs were already sent. However, practically speaking,
1636 // this should not happen, since logs are only sent late into the session.
1637 reporting_service_.metrics_log_store()->Purge();
1638 }
1639
1640 // static
SnapshotDeltasAndFinalizeLog(std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,std::unique_ptr<MetricsLog> log,bool truncate_events,absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,std::string && current_app_version,std::string && signing_key)1641 MetricsService::FinalizedLog MetricsService::SnapshotDeltasAndFinalizeLog(
1642 std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,
1643 std::unique_ptr<MetricsLog> log,
1644 bool truncate_events,
1645 absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1646 std::string&& current_app_version,
1647 std::string&& signing_key) {
1648 log_histogram_writer->SnapshotStatisticsRecorderDeltas();
1649 return FinalizeLog(std::move(log), truncate_events, std::move(close_time),
1650 current_app_version, signing_key);
1651 }
1652
1653 // static
1654 MetricsService::FinalizedLog
SnapshotUnloggedSamplesAndFinalizeLog(MetricsLogHistogramWriter * log_histogram_writer,std::unique_ptr<MetricsLog> log,bool truncate_events,absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,std::string && current_app_version,std::string && signing_key)1655 MetricsService::SnapshotUnloggedSamplesAndFinalizeLog(
1656 MetricsLogHistogramWriter* log_histogram_writer,
1657 std::unique_ptr<MetricsLog> log,
1658 bool truncate_events,
1659 absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1660 std::string&& current_app_version,
1661 std::string&& signing_key) {
1662 log_histogram_writer->SnapshotStatisticsRecorderUnloggedSamples();
1663 return FinalizeLog(std::move(log), truncate_events, std::move(close_time),
1664 current_app_version, signing_key);
1665 }
1666
1667 // static
FinalizeLog(std::unique_ptr<MetricsLog> log,bool truncate_events,absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,const std::string & current_app_version,const std::string & signing_key)1668 MetricsService::FinalizedLog MetricsService::FinalizeLog(
1669 std::unique_ptr<MetricsLog> log,
1670 bool truncate_events,
1671 absl::optional<ChromeUserMetricsExtension::RealLocalTime> close_time,
1672 const std::string& current_app_version,
1673 const std::string& signing_key) {
1674 DCHECK(log->uma_proto()->has_record_id());
1675 std::string log_data;
1676 log->FinalizeLog(truncate_events, current_app_version, std::move(close_time),
1677 &log_data);
1678
1679 FinalizedLog finalized_log;
1680 finalized_log.uncompressed_log_size = log_data.size();
1681 finalized_log.log_info = std::make_unique<UnsentLogStore::LogInfo>();
1682 finalized_log.log_info->Init(log_data, signing_key, log->log_metadata());
1683 return finalized_log;
1684 }
1685
1686 } // namespace metrics
1687