chromium/components/metrics/metrics_service.cc

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//------------------------------------------------------------------------------
// Description of a MetricsService instance's life cycle.
//
// OVERVIEW
//
// A MetricsService instance is typically created at application startup.  It is
// the central controller for the acquisition of log data, and the automatic
// transmission of that log data to an external server.  Its major job is to
// manage logs, grouping them for transmission, and transmitting them.  As part
// of its grouping, MS finalizes logs by including some just-in-time gathered
// memory statistics, snapshotting the current stats of numerous histograms,
// closing the logs, translating to protocol buffer format, and compressing the
// results for transmission.  Transmission includes submitting a compressed log
// as data in a URL-post, and retransmitting (or retaining at process
// termination) if the attempted transmission failed.  Retention across process
// terminations is done using the PrefServices facilities. The retained logs
// (the ones that never got transmitted) are compressed and base64-encoded
// before being persisted.
//
// Logs fall into one of two categories: "initial logs," and "ongoing logs."
// There is at most one initial log sent for each complete run of Chrome (from
// startup, to browser shutdown).  An initial log is generally transmitted some
// short time (1 minute?) after startup, and includes stats such as recent crash
// info, the number and types of plugins, etc.  The external server's response
// to the initial log conceptually tells this MS if it should continue
// transmitting logs (during this session). The server response can actually be
// much more detailed, and always includes (at a minimum) how often additional
// ongoing logs should be sent.
//
// After the above initial log, a series of ongoing logs will be transmitted.
// The first ongoing log actually begins to accumulate information stating when
// the MS was first constructed.  Note that even though the initial log is
// commonly sent a full minute after startup, the initial log does not include
// much in the way of user stats.   The most common interlog period (delay)
// is 30 minutes. That time period starts when the first user action causes a
// logging event.  This means that if there is no user action, there may be long
// periods without any (ongoing) log transmissions.  Ongoing logs typically
// contain very detailed records of user activities (ex: opened tab, closed
// tab, fetched URL, maximized window, etc.)  In addition, just before an
// ongoing log is closed out, a call is made to gather memory statistics.  Those
// memory statistics are deposited into a histogram, and the log finalization
// code is then called.  In the finalization, a call to a Histogram server
// acquires a list of all local histograms that have been flagged for upload
// to the UMA server.  The finalization also acquires the most recent number
// of page loads, along with any counts of renderer or plugin crashes.
//
// When the browser shuts down, there will typically be a fragment of an ongoing
// log that has not yet been transmitted.  At shutdown time, that fragment is
// closed (including snapshotting histograms), and persisted, for potential
// transmission during a future run of the product.
//
// There are two slightly abnormal shutdown conditions.  There is a
// "disconnected scenario," and a "really fast startup and shutdown" scenario.
// In the "never connected" situation, the user has (during the running of the
// process) never established an internet connection.  As a result, attempts to
// transmit the initial log have failed, and a lot(?) of data has accumulated in
// the ongoing log (which didn't yet get closed, because there was never even a
// contemplation of sending it).  There is also a kindred "lost connection"
// situation, where a loss of connection prevented an ongoing log from being
// transmitted, and a (still open) log was stuck accumulating a lot(?) of data,
// while the earlier log retried its transmission.  In both of these
// disconnected situations, two logs need to be, and are, persistently stored
// for future transmission.
//
// The other unusual shutdown condition, termed "really fast startup and
// shutdown," involves the deliberate user termination of the process before
// the initial log is even formed or transmitted. In that situation, no logging
// is done, but the historical crash statistics remain (unlogged) for inclusion
// in a future run's initial log.  (i.e., we don't lose crash stats).
//
// With the above overview, we can now describe the state machine's various
// states, based on the State enum specified in the state_ member.  Those states
// are:
//
//  CONSTRUCTED,          // Constructor was called.
//  INITIALIZED,          // InitializeMetricsRecordingState() was called.
//  INIT_TASK_SCHEDULED,  // Waiting for deferred init tasks to finish.
//  INIT_TASK_DONE,       // Waiting for timer to send the first ongoing log.
//  SENDING_LOGS,         // Sending logs and creating new ones when we run out.
//
// In more detail, we have:
//
//    INIT_TASK_SCHEDULED,    // Waiting for deferred init tasks to finish.
// Typically about 30 seconds after startup, a task is sent to a background
// thread to perform deferred (lower priority and slower) initialization steps
// such as getting the list of plugins.  That task will (when complete) make an
// async callback (via a Task) to indicate the completion.
//
//    INIT_TASK_DONE,         // Waiting for timer to send first ongoing log.
// The callback has arrived, and it is now possible for an ongoing log to be
// created.  This callback typically arrives back less than one second after
// the deferred init task is dispatched.
//
//    SENDING_LOGS,  // Sending logs and creating new ones when we run out.
// Logs from previous sessions have been loaded, and an optional initial
// stability log has been created. We will send all of these logs, and when
// they run out, we will start cutting new logs to send.  We will also cut a new
// log if we expect a shutdown.
//
// The progression through the above states is simple, and sequential.
// States proceed from INITIALIZED to SENDING_LOGS, and remain in the latter
// until shutdown.
//
// Also note that whenever we successfully send a log, we mirror the list
// of logs into the PrefService. This ensures that IF we crash, we won't start
// up and retransmit our old logs again.
//
// Due to race conditions, it is always possible that a log file could be sent
// twice.  For example, if a log file is sent, but not yet acknowledged by
// the external server, and the user shuts down, then a copy of the log may be
// saved for re-transmission.  These duplicates could be filtered out server
// side, but are not expected to be a significant problem.
//
//
//------------------------------------------------------------------------------

#include "components/metrics/metrics_service.h"

#include <stddef.h>

#include <algorithm>
#include <memory>
#include <string_view>
#include <utility>

#include "base/callback_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_flattener.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/histogram_macros_local.h"
#include "base/metrics/histogram_samples.h"
#include "base/metrics/persistent_histogram_allocator.h"
#include "base/metrics/statistics_recorder.h"
#include "base/metrics/user_metrics.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/metrics/clean_exit_beacon.h"
#include "components/metrics/environment_recorder.h"
#include "components/metrics/field_trials_provider.h"
#include "components/metrics/metrics_features.h"
#include "components/metrics/metrics_log.h"
#include "components/metrics/metrics_log_uploader.h"
#include "components/metrics/metrics_logs_event_manager.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/metrics/metrics_rotation_scheduler.h"
#include "components/metrics/metrics_service_client.h"
#include "components/metrics/metrics_service_observer.h"
#include "components/metrics/metrics_state_manager.h"
#include "components/metrics/metrics_switches.h"
#include "components/metrics/persistent_system_profile.h"
#include "components/metrics/stability_metrics_provider.h"
#include "components/metrics/url_constants.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/entropy_provider.h"

#if !BUILDFLAG(IS_ANDROID)
#include "components/keep_alive_registry/keep_alive_registry.h"
#include "components/keep_alive_registry/keep_alive_types.h"
#include "components/keep_alive_registry/scoped_keep_alive.h"
#endif  // !BUILDFLAG(IS_ANDROID)

namespace metrics {
namespace {

// Used to write histogram data to a log. Does not take ownership of the log.
class IndependentFlattener : public base::HistogramFlattener {};

// Used to mark histogram samples as reported so that they are not included in
// the next log. A histogram's snapshot samples are simply discarded/ignored
// when attempting to record them through this |HistogramFlattener|.
class DiscardingFlattener : public base::HistogramFlattener {};

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// Emits a histogram upon instantiation, and on destruction. Used to measure how
// often the browser is ungracefully killed between two different points. In
// particular, currently, this is used on mobile to measure how often the
// browser is killed while finalizing a log, right after backgrounding. This
// scenario is prone to data loss because a histogram may have been snapshotted
// and put into a log, but the browser was killed before it could be fully
// finalized and stored.
//
// TODO(crbug.com/40213327): Consider improving this. In particular, the
// "Started" bucket is emitted before finalizing the log, and the "Finished"
// bucket is emitted after. Hence, the latter will be reported in a different
// log, which may cause a "lag" and/or bias (e.g. if the latter log is more
// prone to loss). A better way to do this is to allocate an object on the
// persistent memory upon instantiation, and flip a bit in it upon destruction.
// A future session that will consume this persistent memory should take care of
// emitting the histogram samples.
class ScopedTerminationChecker {
 public:
  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused.
  enum class Status {
    kStarted = 0,
    kFinished = 1,
    kMaxValue = kFinished,
  };

  explicit ScopedTerminationChecker(std::string_view histogram_name) {
    // Do nothing if the persistent histogram system is not being used.
    // Otherwise, the "Finished" bucket may be more prone to loss, which may
    // incorrectly make it seem like the browser was killed in between the
    // scoped code.
    if (!base::GlobalHistogramAllocator::Get()) {
      return;
    }

    active_ = true;
    histogram_name_ = histogram_name;
    base::UmaHistogramEnumeration(histogram_name_, Status::kStarted);
  }

  ScopedTerminationChecker(const ScopedTerminationChecker& other) = delete;
  ScopedTerminationChecker& operator=(const ScopedTerminationChecker& other) =
      delete;

  ~ScopedTerminationChecker() {
    if (!active_) {
      return;
    }
    base::UmaHistogramEnumeration(histogram_name_, Status::kFinished);
  }

 private:
  // Name of the histogram to emit to upon instantiation/destruction.
  std::string histogram_name_;

  // Whether or not this will emit histograms. In particular, if this browser
  // session does not make use of persistent memory, this will be false, and
  // this object will do nothing.
  bool active_ = false;
};
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

// The delay, in seconds, after starting recording before doing expensive
// initialization work.
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
// On mobile devices, a significant portion of sessions last less than a minute.
// Use a shorter timer on these platforms to avoid losing data.
// TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
//                    that it occurs after the user gets their initial page.
const int kInitializationDelaySeconds = 5;
#else
const int kInitializationDelaySeconds =;
#endif

// The browser last live timestamp is updated every 15 minutes.
const int kUpdateAliveTimestampSeconds =;

#if BUILDFLAG(IS_CHROMEOS_ASH)
enum UserLogStoreState {
  kSetPostSendLogsState = 0,
  kSetPreSendLogsState = 1,
  kUnsetPostSendLogsState = 2,
  kUnsetPreSendLogsState = 3,
  kMaxValue = kUnsetPreSendLogsState,
};

void RecordUserLogStoreState(UserLogStoreState state) {
  base::UmaHistogramEnumeration("UMA.CrosPerUser.UserLogStoreState", state);
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

}  // namespace

// static
void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {}

MetricsService::MetricsService(MetricsStateManager* state_manager,
                               MetricsServiceClient* client,
                               PrefService* local_state)
    :{}

MetricsService::~MetricsService() {}

void MetricsService::InitializeMetricsRecordingState() {}

void MetricsService::Start() {}

void MetricsService::StartRecordingForTests() {}

void MetricsService::StartUpdatingLastLiveTimestamp() {}

void MetricsService::Stop() {}

void MetricsService::EnableReporting() {}

void MetricsService::DisableReporting() {}

std::string MetricsService::GetClientId() const {}

int MetricsService::GetLowEntropySource() {}

int MetricsService::GetOldLowEntropySource() {}

int MetricsService::GetPseudoLowEntropySource() {}

void MetricsService::SetExternalClientId(const std::string& id) {}

bool MetricsService::WasLastShutdownClean() const {}

void MetricsService::EnableRecording() {}

void MetricsService::DisableRecording() {}

bool MetricsService::recording_active() const {}

bool MetricsService::reporting_active() const {}

bool MetricsService::has_unsent_logs() const {}

bool MetricsService::IsMetricsReportingEnabled() const {}

void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {}

void MetricsService::OnApplicationNotIdle() {}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
void MetricsService::OnAppEnterBackground(bool keep_recording_in_background) {
  is_in_foreground_ = false;
  reporting_service_.SetIsInForegound(false);
  if (!keep_recording_in_background) {
    rotation_scheduler_->Stop();
    reporting_service_.Stop();
  }

  state_manager_->LogHasSessionShutdownCleanly(true);
  // Schedule a write, which happens on a different thread.
  local_state_->CommitPendingWrite();

  // Give providers a chance to persist histograms as part of being
  // backgrounded.
  delegating_provider_.OnAppEnterBackground();

  // At this point, there's no way of knowing when the process will be killed,
  // so this has to be treated similar to a shutdown, closing and persisting all
  // logs. Unlike a shutdown, the state is primed to be ready to continue
  // logging and uploading if the process does return.
  if (recording_active() && !IsTooEarlyToCloseLog()) {
    base::UmaHistogramBoolean(
        "UMA.MetricsService.PendingOngoingLogOnBackgrounded",
        pending_ongoing_log_);
#if BUILDFLAG(IS_ANDROID)
    client_->MergeSubprocessHistograms();
#endif  // BUILDFLAG(IS_ANDROID)
    {
      ScopedTerminationChecker scoped_termination_checker(
          "UMA.MetricsService.OnBackgroundedScopedTerminationChecker");
      PushPendingLogsToPersistentStorage(
          MetricsLogsEventManager::CreateReason::kBackgrounded);
    }
    // Persisting logs closes the current log, so start recording a new log
    // immediately to capture any background work that might be done before the
    // process is killed.
    OpenNewLog();
  }
}

void MetricsService::OnAppEnterForeground(bool force_open_new_log) {
  is_in_foreground_ = true;
  reporting_service_.SetIsInForegound(true);
  state_manager_->LogHasSessionShutdownCleanly(false);
  StartSchedulerIfNecessary();

  if (force_open_new_log && recording_active() && !IsTooEarlyToCloseLog()) {
    base::UmaHistogramBoolean(
        "UMA.MetricsService.PendingOngoingLogOnForegrounded",
        pending_ongoing_log_);
#if BUILDFLAG(IS_ANDROID)
    client_->MergeSubprocessHistograms();
#endif  // BUILDFLAG(IS_ANDROID)
    // Because state_ >= SENDING_LOGS, PushPendingLogsToPersistentStorage()
    // will close the log, allowing a new log to be opened.
    PushPendingLogsToPersistentStorage(
        MetricsLogsEventManager::CreateReason::kForegrounded);
    OpenNewLog();
  }
}
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

void MetricsService::OnPageLoadStarted() {}

void MetricsService::LogCleanShutdown() {}

void MetricsService::ClearSavedStabilityMetrics() {}

void MetricsService::MarkCurrentHistogramsAsReported() {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
void MetricsService::SetUserLogStore(
    std::unique_ptr<UnsentLogStore> user_log_store) {
  if (log_store()->has_alternate_ongoing_log_store())
    return;

  if (state_ >= SENDING_LOGS) {
    // Closes the current log so that a new log can be opened in the user log
    // store.
    PushPendingLogsToPersistentStorage(
        MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreSet);
    log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
    OpenNewLog();
    RecordUserLogStoreState(kSetPostSendLogsState);
  } else {
    // Initial log has not yet been created and flushing now would result in
    // incomplete information in the current log.
    //
    // Logs recorded before a user login will be appended to user logs. This
    // should not happen frequently.
    //
    // TODO(crbug.com/40203458): Look for a way to "pause" pre-login logs and
    // flush when INIT_TASK is done.
    log_store()->SetAlternateOngoingLogStore(std::move(user_log_store));
    RecordUserLogStoreState(kSetPreSendLogsState);
  }
}

void MetricsService::UnsetUserLogStore() {
  if (!log_store()->has_alternate_ongoing_log_store()) {
    return;
  }

  if (state_ >= SENDING_LOGS) {
    PushPendingLogsToPersistentStorage(
        MetricsLogsEventManager::CreateReason::kAlternateOngoingLogStoreUnset);
    log_store()->UnsetAlternateOngoingLogStore();
    OpenNewLog();
    RecordUserLogStoreState(kUnsetPostSendLogsState);
    return;
  }

  // Fast startup and logout case. We flush all histograms and discard the
  // current log. This is to prevent histograms captured during the user
  // session from leaking into local state logs.
  // TODO(crbug.com/40245274): Consider not flushing histograms here.

  // Discard histograms.
  DiscardingFlattener flattener;
  base::HistogramSnapshotManager histogram_snapshot_manager(&flattener);
  delegating_provider_.RecordHistogramSnapshots(&histogram_snapshot_manager);
  base::StatisticsRecorder::PrepareDeltas(
      /*include_persistent=*/true, /*flags_to_set=*/base::Histogram::kNoFlags,
      /*required_flags=*/base::Histogram::kUmaTargetedHistogramFlag,
      &histogram_snapshot_manager);

  // Discard the current log, don't store it and stop recording.
  CHECK(current_log_);
  current_log_.reset();
  DisableRecording();

  log_store()->UnsetAlternateOngoingLogStore();
  RecordUserLogStoreState(kUnsetPreSendLogsState);
}

bool MetricsService::HasUserLogStore() {
  return log_store()->has_alternate_ongoing_log_store();
}

void MetricsService::InitPerUserMetrics() {
  client_->InitPerUserMetrics();
}

std::optional<bool> MetricsService::GetCurrentUserMetricsConsent() const {
  return client_->GetCurrentUserMetricsConsent();
}

std::optional<std::string> MetricsService::GetCurrentUserId() const {
  return client_->GetCurrentUserId();
}

void MetricsService::UpdateCurrentUserMetricsConsent(
    bool user_metrics_consent) {
  client_->UpdateCurrentUserMetricsConsent(user_metrics_consent);
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS)
void MetricsService::ResetClientId() {
  // Pref must be cleared in order for ForceClientIdCreation to generate a new
  // client ID.
  local_state_->ClearPref(prefs::kMetricsClientID);
  local_state_->ClearPref(prefs::kMetricsLogFinalizedRecordId);
  local_state_->ClearPref(prefs::kMetricsLogRecordId);
  state_manager_->ForceClientIdCreation();
  client_->SetMetricsClientId(state_manager_->client_id());
}
#endif  // BUILDFLAG(IS_CHROMEOS)

variations::SyntheticTrialRegistry*
MetricsService::GetSyntheticTrialRegistry() {}

base::TimeDelta MetricsService::GetInitializationDelay() {}

base::TimeDelta MetricsService::GetUpdateLastAliveTimestampDelay() {}

bool MetricsService::StageCurrentLogForTest() {}

//------------------------------------------------------------------------------
// private methods
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// Initialization methods

void MetricsService::InitializeMetricsState() {}

void MetricsService::OnUserAction(const std::string& action,
                                  base::TimeTicks action_time) {}

void MetricsService::FinishedInitTask() {}

void MetricsService::GetUptimes(PrefService* pref,
                                base::TimeDelta* incremental_uptime,
                                base::TimeDelta* uptime) {}

//------------------------------------------------------------------------------
// Recording control methods

void MetricsService::OpenNewLog(bool call_providers) {}

MetricsService::FinalizedLog::FinalizedLog() = default;
MetricsService::FinalizedLog::~FinalizedLog() = default;
MetricsService::FinalizedLog::FinalizedLog(FinalizedLog&& other) = default;
MetricsService::FinalizedLog& MetricsService::FinalizedLog::operator=(
    FinalizedLog&& other) = default;

MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
    MetricsLog* log)
    :{}

MetricsService::MetricsLogHistogramWriter::MetricsLogHistogramWriter(
    MetricsLog* log,
    base::HistogramBase::Flags required_flags)
    :{}

MetricsService::MetricsLogHistogramWriter::~MetricsLogHistogramWriter() =
    default;

void MetricsService::MetricsLogHistogramWriter::
    SnapshotStatisticsRecorderDeltas() {}

void MetricsService::MetricsLogHistogramWriter::
    SnapshotStatisticsRecorderUnloggedSamples() {}

void MetricsService::MetricsLogHistogramWriter::NotifyLogBeingFinalized() {}

MetricsService::IndependentMetricsLoader::IndependentMetricsLoader(
    std::unique_ptr<MetricsLog> log,
    std::string app_version,
    std::string signing_key)
    :{}

MetricsService::IndependentMetricsLoader::~IndependentMetricsLoader() = default;

void MetricsService::IndependentMetricsLoader::Run(
    base::OnceCallback<void(bool)> done_callback,
    MetricsProvider* metrics_provider) {}

void MetricsService::IndependentMetricsLoader::FinalizeLog() {}

bool MetricsService::IndependentMetricsLoader::HasFinalizedLog() {}

MetricsService::FinalizedLog
MetricsService::IndependentMetricsLoader::ReleaseFinalizedLog() {}

void MetricsService::StartInitTask() {}

void MetricsService::CloseCurrentLog(
    bool async,
    MetricsLogsEventManager::CreateReason reason,
    base::OnceClosure log_stored_callback) {}

void MetricsService::StoreFinalizedLog(
    MetricsLog::LogType log_type,
    MetricsLogsEventManager::CreateReason reason,
    base::OnceClosure done_callback,
    FinalizedLog finalized_log) {}

void MetricsService::MaybeCleanUpAndStoreFinalizedLog(
    std::unique_ptr<MetricsLogHistogramWriter> log_histogram_writer,
    MetricsLog::LogType log_type,
    MetricsLogsEventManager::CreateReason reason,
    base::OnceClosure done_callback,
    FinalizedLog finalized_log) {}

void MetricsService::PushPendingLogsToPersistentStorage(
    MetricsLogsEventManager::CreateReason reason) {}

//------------------------------------------------------------------------------
// Transmission of logs methods

void MetricsService::StartSchedulerIfNecessary() {}

void MetricsService::StartScheduledUpload() {}

void MetricsService::OnFinalLogInfoCollectionDone() {}

void MetricsService::OnAsyncPeriodicOngoingLogStored() {}

bool MetricsService::PrepareInitialStabilityLog(
    const std::string& prefs_previous_version) {}

void MetricsService::RegisterMetricsProvider(
    std::unique_ptr<MetricsProvider> provider) {}

void MetricsService::CheckForClonedInstall() {}

bool MetricsService::ShouldResetClientIdsOnClonedInstall() {}

std::unique_ptr<MetricsLog> MetricsService::CreateLog(
    MetricsLog::LogType log_type) {}

void MetricsService::AddLogsObserver(
    MetricsLogsEventManager::Observer* observer) {}

void MetricsService::RemoveLogsObserver(
    MetricsLogsEventManager::Observer* observer) {}

base::CallbackListSubscription MetricsService::AddEnablementObserver(
    const base::RepeatingCallback<void(bool)>& observer) {}

void MetricsService::SetPersistentSystemProfile(
    const std::string& serialized_proto,
    bool complete) {}

// static
std::string MetricsService::RecordCurrentEnvironmentHelper(
    MetricsLog* log,
    PrefService* local_state,
    DelegatingProvider* delegating_provider) {}

void MetricsService::RecordCurrentEnvironment(MetricsLog* log, bool complete) {}

void MetricsService::PrepareProviderMetricsLogDone(
    std::unique_ptr<IndependentMetricsLoader> loader,
    bool success) {}

bool MetricsService::PrepareProviderMetricsLog() {}

void MetricsService::PrepareProviderMetricsTask() {}

void MetricsService::UpdateLastLiveTimestampTask() {}

bool MetricsService::IsTooEarlyToCloseLog() {}

void MetricsService::OnClonedInstallDetected() {}

// static
MetricsService::FinalizedLog MetricsService::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) {}

// static
MetricsService::FinalizedLog
MetricsService::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) {}

// static
MetricsService::FinalizedLog MetricsService::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) {}

}  // namespace metrics