chromium/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc

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

#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/40285824): Remove this and convert code to safer constructs.
#pragma allow_unsafe_buffers
#endif

#include "chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h"

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>

#include "base/allocator/partition_alloc_support.h"
#include "base/command_line.h"
#include "base/cpu.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/sparse_histogram.h"
#include "base/power_monitor/power_monitor_buildflags.h"
#include "base/rand_util.h"
#include "base/strings/strcat.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
#include "base/trace_event/trace_log.h"
#include "base/version.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "build/config/compiler/compiler_buildflags.h"
#include "chrome/browser/about_flags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/buildflags.h"
#include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/google/google_brand.h"
#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
#include "chrome/browser/metrics/process_memory_metrics_emitter.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/browser/ui/performance_controls/performance_controls_metrics.h"
#include "chrome/common/chrome_switches.h"
#include "components/flags_ui/pref_service_flags_storage.h"
#include "components/metrics/android_metrics_helper.h"
#include "components/performance_manager/public/features.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/policy/core/common/management/management_service.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/synthetic_trials.h"
#include "components/variations/variations_ids_provider.h"
#include "components/variations/variations_switches.h"
#include "components/version_info/version_info_values.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/content_switches.h"
#include "crypto/unexportable_key.h"
#include "crypto/unexportable_key_metrics.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/browser_metrics.h"
#include "ui/base/pointer/pointer_device.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/screen.h"

#if !BUILDFLAG(IS_ANDROID)
#include "base/power_monitor/battery_state_sampler.h"
#include "chrome/browser/metrics/first_web_contents_profiler.h"
#include "chrome/browser/metrics/power/battery_discharge_reporter.h"
#include "chrome/browser/metrics/power/power_metrics_reporter.h"
#include "chrome/browser/metrics/power/process_monitor.h"
#include "chrome/browser/metrics/tab_stats/tab_stats_tracker.h"
#endif  // !BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_ANDROID)
#if defined(__arm__)
#include <cpu-features.h>
#endif
#include "base/android/build_info.h"
#include "chrome/browser/flags/android/chrome_session_state.h"
#endif  // BUILDFLAG(IS_ANDROID)

// TODO(crbug.com/40118868): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
#if defined(__GLIBC__) && (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
#include <gnu/libc-version.h>

#include "base/linux_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)

#if BUILDFLAG(IS_WIN)
#include <windows.h>

#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/win/registry.h"
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#include "chrome/browser/metrics/key_credential_manager_support_reporter_win.h"
#include "chrome/browser/shell_integration_win.h"
#include "chrome/installer/util/taskbar_util.h"
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chromeos/crosapi/cpp/crosapi_constants.h"
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

#if BUILDFLAG(IS_LINUX)
#include "chrome/browser/metrics/pressure/pressure_metrics_reporter.h"
#endif  // BUILDFLAG(IS_LINUX)

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "components/user_manager/user_manager.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "components/power_metrics/system_power_monitor.h"
#endif

#if BUILDFLAG(IS_MAC)
#include "chrome/common/chrome_version.h"
#endif  // BUILDFLAG(IS_MAC)

namespace {

// The number of restarts to wait until removing the enable-benchmarking flag.
constexpr int kEnableBenchmarkingCountdownDefault =;
constexpr char kEnableBenchmarkingPrefId[] =;

#if BUILDFLAG(IS_MAC)
constexpr char kUnexportableKeysKeychainAccessGroup[] =
    MAC_TEAM_IDENTIFIER_STRING "." MAC_BUNDLE_IDENTIFIER_STRING
                               ".unexportable-keys";
#endif  // BUILDFLAG(IS_MAC)

void RecordMemoryMetrics();

// Gets the delay for logging memory related metrics. Minimum is 1 second.
base::TimeDelta GetDelayForNextMemoryLogTest() {}

// Records memory metrics after a delay.
void RecordMemoryMetricsAfterDelay() {}

// Records memory metrics, and then triggers memory collection after a delay.
void RecordMemoryMetrics() {}

// These values are written to logs.  New enum values can be added, but existing
// enums must never be renumbered or deleted and reused unless the histogram is
// renamed.
enum class UmaLinuxDistro {};

enum UMALinuxGlibcVersion : uint32_t {};

#if BUILDFLAG(IS_CHROMEOS_LACROS)
// These values are written to logs.  New enum values can be added, but existing
// enums must never be renumbered or deleted and reused.
enum class ChromeOSChannel {
  kUnknown = 0,
  kCanary = 1,
  kDev = 2,
  kBeta = 3,
  kStable = 4,
  kMaxValue = kStable,
};

// Records the underlying Chrome OS release channel, which may be different than
// the Lacros browser's release channel.
void RecordChromeOSChannel() {
  ChromeOSChannel os_channel = ChromeOSChannel::kUnknown;
  std::string release_track;
  if (base::SysInfo::GetLsbReleaseValue(crosapi::kChromeOSReleaseTrack,
                                        &release_track)) {
    if (release_track == crosapi::kReleaseChannelStable)
      os_channel = ChromeOSChannel::kStable;
    else if (release_track == crosapi::kReleaseChannelBeta)
      os_channel = ChromeOSChannel::kBeta;
    else if (release_track == crosapi::kReleaseChannelDev)
      os_channel = ChromeOSChannel::kDev;
    else if (release_track == crosapi::kReleaseChannelCanary)
      os_channel = ChromeOSChannel::kCanary;
  }
  base::UmaHistogramEnumeration("ChromeOS.Lacros.OSChannel", os_channel);
}
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

void RecordMicroArchitectureStats() {}

#if BUILDFLAG(IS_LINUX)
void RecordLinuxDistroSpecific(const std::string& version_string,
                               size_t parts,
                               const char* histogram_name) {}

// Some releases may have multiple names like "opensuse_leap", "opensuse leap",
// or "opensuseleap".  Trim non-alphanumeric characters so they all map to the
// same name.
std::string TrimLinuxDistro(const std::string& distro) {}

void RecordLinuxDistro() {}
#endif  // BUILDFLAG(IS_LINUX)

void RecordLinuxGlibcVersion() {}

#if BUILDFLAG(IS_WIN)
// Record the UMA histogram when a response is received.
void OnIsPinnedToTaskbarResult(bool succeeded, bool is_pinned_to_taskbar) {
  // Used for histograms; do not reorder.
  enum Result { NOT_PINNED = 0, PINNED = 1, FAILURE = 2, NUM_RESULTS };

  Result result = FAILURE;
  if (succeeded)
    result = is_pinned_to_taskbar ? PINNED : NOT_PINNED;

  base::UmaHistogramEnumeration("Windows.IsPinnedToTaskbar", result,
                                NUM_RESULTS);

  // If Chrome is not pinned to taskbar, clear the recording that the installer
  // pinned Chrome to the taskbar, so that if the user pins Chrome back to the
  // taskbar, we don't count launches as coming from an installer-pinned
  // shortcut.  TODO(crbug.com/40235395): We currently only check if
  // Chrome is pinned to the taskbar 1 out every 100 launches, which makes this
  // less meaningful, so if keeping track of whether the installer pinned Chrome
  // to the taskbar is important, we need to deal with that.

  // Record whether or not the user unpinned an installer pin of Chrome. Records
  // true if the installer pinned Chrome, and it's not pinned on this startup,
  // false if the installer pinned Chrome, and it's still pinned.
  if (GetInstallerPinnedChromeToTaskbar().value_or(false)) {
    if (result == NOT_PINNED)
      SetInstallerPinnedChromeToTaskbar(false);
    if (result != FAILURE) {
      base::UmaHistogramBoolean("Windows.InstallerPinUnpinned",
                                result == NOT_PINNED);
    }
  }
}

// Records the pinned state of the current executable into a histogram. Should
// be called on a background thread, with low priority, to avoid slowing down
// startup.
void RecordIsPinnedToTaskbarHistogram() {
  shell_integration::win::GetIsPinnedToTaskbarState(
      base::BindOnce(&OnIsPinnedToTaskbarResult));
}

// This registry key is not fully documented but there is information on it
// here:
// https://blogs.blackberry.com/en/2017/10/windows-10-parallel-loading-breakdown.
bool IsParallelDllLoadingEnabled() {
  base::FilePath exe_path;
  if (!base::PathService::Get(base::FILE_EXE, &exe_path))
    return false;
  const wchar_t kIFEOKey[] =
      L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution "
      L"Options\\";
  std::wstring browser_process_key = kIFEOKey + exe_path.BaseName().value();

  base::win::RegKey key;
  if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, browser_process_key.c_str(),
                                KEY_QUERY_VALUE))
    return true;

  const wchar_t kMaxLoaderThreads[] = L"MaxLoaderThreads";
  DWORD max_loader_threads = 0;
  if (ERROR_SUCCESS != key.ReadValueDW(kMaxLoaderThreads, &max_loader_threads))
    return true;

  // Note: If LoaderThreads is 0, it will be set to the default value of 4.
  return max_loader_threads != 1;
}

// Records the presence (bad) or absence (good) of AcLayers.dll in the browser
// process.
void RecordAppCompatMetrics() {
  HMODULE mod = ::GetModuleHandleW(L"AcLayers.dll");
  base::UmaHistogramBoolean("Windows.AcLayersLoaded", !!mod);
}

#endif  // BUILDFLAG(IS_WIN)

void RecordDisplayHDRStatus(const display::Display& display) {}

// Called on a background thread, with low priority to avoid slowing down
// startup with metrics that aren't trivial to compute.
void RecordStartupMetrics() {}

}  // namespace

#if BUILDFLAG(IS_ANDROID)
bool IsBundleForMixedDeviceAccordingToVersionCode(
    const std::string& version_code) {
  // Primary bitness of the bundle is encoded in the last digit of the version
  // code. And the variant (package name) is encoded in the second to last.
  //
  // From build/util/android_chrome_version.py:
  //       'arm': {
  //          '32': 0,
  //          '32_64': 1,
  //          '64_32': 2,
  //          '64_32_high': 3,
  //          '64': 4,
  //      },
  //      'intel': {
  //          '32': 6,
  //          '32_64': 7,
  //          '64_32': 8,
  //          '64': 9,
  //      },
  //
  //      _PACKAGE_NAMES = {
  //          'CHROME': 0,
  //          'CHROME_MODERN': 10,
  //          'MONOCHROME': 20,
  //          'TRICHROME': 30,
  //          [...]

  if (version_code.length() < 2) {
    return false;
  }

  // '32' and '64' bundles go on 32bit-only and 64bit-only devices, so exclude
  // them.
  std::set<char> arch_codes_mixed = {'1', '2', '3', '7', '8'};
  char arch_code = version_code.back();

  // Only 'TRICHROME' supports 64-bit.
  constexpr char kTriChromeVariant = '3';
  char variant = version_code[version_code.length() - 2];

  return arch_codes_mixed.count(arch_code) > 0 && variant == kTriChromeVariant;
}
#endif  // BUILDFLAG(IS_ANDROID)

ChromeBrowserMainExtraPartsMetrics::ChromeBrowserMainExtraPartsMetrics()
    :{}

ChromeBrowserMainExtraPartsMetrics::~ChromeBrowserMainExtraPartsMetrics() =
    default;

void ChromeBrowserMainExtraPartsMetrics::PreCreateThreads() {}

void ChromeBrowserMainExtraPartsMetrics::PostCreateMainMessageLoop() {}

void ChromeBrowserMainExtraPartsMetrics::PreProfileInit() {}

void ChromeBrowserMainExtraPartsMetrics::PreBrowserStart() {}

void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() {}

void ChromeBrowserMainExtraPartsMetrics::PreMainMessageLoopRun() {}

void ChromeBrowserMainExtraPartsMetrics::PostDestroyThreads() {}

void ChromeBrowserMainExtraPartsMetrics::RegisterPrefs(
    PrefRegistrySimple* registry) {}

void ChromeBrowserMainExtraPartsMetrics::HandleEnableBenchmarkingCountdown(
    PrefService* pref_service,
    std::unique_ptr<flags_ui::FlagsStorage> storage,
    flags_ui::FlagAccess access) {}

void ChromeBrowserMainExtraPartsMetrics::
    HandleEnableBenchmarkingCountdownAsync() {}

void ChromeBrowserMainExtraPartsMetrics::OnDisplayAdded(
    const display::Display& new_display) {}

void ChromeBrowserMainExtraPartsMetrics::OnDisplaysRemoved(
    const display::Displays& removed_displays) {}

void ChromeBrowserMainExtraPartsMetrics::OnDisplayMetricsChanged(
    const display::Display& display,
    uint32_t changed_metrics) {}

void ChromeBrowserMainExtraPartsMetrics::EmitDisplaysChangedMetric() {}

namespace chrome {

void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts) {}

}  // namespace chrome