blob: b8d130be44392c90c0cff3f0e98c796127fc84a6 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/performance_manager/metrics/metrics_provider.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/process/process_metrics.h"
#include "base/system/sys_info.h"
#include "base/timer/timer.h"
#include "chrome/browser/performance_manager/public/user_tuning/user_performance_tuning_manager.h"
#include "components/performance_manager/public/user_tuning/prefs.h"
#include "components/prefs/pref_service.h"
#include "ui/accessibility/ax_mode.h"
#include "ui/accessibility/platform/ax_platform_node.h"
using performance_manager::user_tuning::prefs::HighEfficiencyModeState;
using performance_manager::user_tuning::prefs::kHighEfficiencyModeState;
namespace performance_manager {
namespace {
MetricsProvider* g_metrics_provider = nullptr;
uint64_t kBytesPerMb = 1024 * 1024;
#if BUILDFLAG(IS_MAC)
uint64_t kKilobytesPerMb = 1024;
#endif
ui::AXMode::ModeFlagHistogramValue ModeFlagsToEnum(uint32_t mode_flags) {
switch (mode_flags) {
case ui::AXMode::kNativeAPIs:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_NATIVE_APIS;
case ui::AXMode::kWebContents:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_WEB_CONTENTS;
case ui::AXMode::kInlineTextBoxes:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_INLINE_TEXT_BOXES;
case ui::AXMode::kScreenReader:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_SCREEN_READER;
case ui::AXMode::kHTML:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_HTML;
case ui::AXMode::kHTMLMetadata:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_HTML_METADATA;
case ui::AXMode::kLabelImages:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_LABEL_IMAGES;
case ui::AXMode::kPDF:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF;
case ui::AXMode::kPDFOcr:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_PDF_OCR;
default:
return ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_MAX;
}
}
void MaybeRecordAccessibilityModeFlags(const ui::AXMode& mode,
uint32_t mode_flags) {
if (mode.has_mode(mode_flags)) {
ui::AXMode::ModeFlagHistogramValue mode_enum = ModeFlagsToEnum(mode_flags);
if (mode_enum != ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_MAX) {
UMA_HISTOGRAM_ENUMERATION(
"PerformanceManager.Experimental.AccessibilityModeFlag", mode_enum,
ui::AXMode::ModeFlagHistogramValue::UMA_AX_MODE_MAX);
}
}
}
} // namespace
// static
MetricsProvider* MetricsProvider::GetInstance() {
DCHECK(g_metrics_provider);
return g_metrics_provider;
}
MetricsProvider::~MetricsProvider() {
DCHECK_EQ(this, g_metrics_provider);
g_metrics_provider = nullptr;
}
void MetricsProvider::Initialize() {
DCHECK(!initialized_);
pref_change_registrar_.Init(local_state_);
pref_change_registrar_.Add(
kHighEfficiencyModeState,
base::BindRepeating(&MetricsProvider::OnTuningModesChanged,
base::Unretained(this)));
performance_manager::user_tuning::UserPerformanceTuningManager::GetInstance()
->AddObserver(this);
battery_saver_enabled_ = performance_manager::user_tuning::
UserPerformanceTuningManager::GetInstance()
->IsBatterySaverActive();
initialized_ = true;
current_mode_ = ComputeCurrentMode();
}
void MetricsProvider::RecordA11yFlags() {
ui::AXMode mode = ui::AXPlatformNode::GetAccessibilityMode();
bool is_mode_on = !mode.is_mode_off();
UMA_HISTOGRAM_BOOLEAN(
"PerformanceManager.Experimental.HasAccessibilityModeFlag", is_mode_on);
if (is_mode_on) {
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kNativeAPIs);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kWebContents);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kInlineTextBoxes);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kScreenReader);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kHTML);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kHTMLMetadata);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kLabelImages);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kPDF);
MaybeRecordAccessibilityModeFlags(mode, ui::AXMode::kPDFOcr);
}
}
void MetricsProvider::ProvideCurrentSessionData(
metrics::ChromeUserMetricsExtension* uma_proto) {
// It's valid for this to be called when `initialized_` is false if the finch
// features controlling battery saver and high efficiency are disabled.
// TODO(crbug.com/1348590): CHECK(initialized_) when the features are enabled
// and removed.
base::UmaHistogramEnumeration("PerformanceManager.UserTuning.EfficiencyMode",
current_mode_);
// Set `current_mode_` to represent the state of the modes as they are now, so
// that this mode is what is adequately reported at the next report, unless it
// changes in the meantime.
current_mode_ = ComputeCurrentMode();
RecordA11yFlags();
}
MetricsProvider::MetricsProvider(PrefService* local_state)
: local_state_(local_state) {
DCHECK(!g_metrics_provider);
g_metrics_provider = this;
available_memory_metrics_timer_.Start(
FROM_HERE, base::Minutes(2),
base::BindRepeating(&MetricsProvider::RecordAvailableMemoryMetrics,
base::Unretained(this)));
}
void MetricsProvider::OnBatterySaverModeChanged(bool is_active) {
battery_saver_enabled_ = is_active;
OnTuningModesChanged();
}
void MetricsProvider::OnTuningModesChanged() {
EfficiencyMode new_mode = ComputeCurrentMode();
// If the mode changes between UMA reports, mark it as Mixed for this
// interval.
if (current_mode_ != new_mode) {
current_mode_ = EfficiencyMode::kMixed;
}
}
MetricsProvider::EfficiencyMode MetricsProvider::ComputeCurrentMode() const {
// It's valid for this to be uninitialized if the battery saver/high
// efficiency modes are unavailable. In that case, the browser is running in
// normal mode, so return kNormal.
// TODO(crbug.com/1348590): Change this to a DCHECK when the features are
// enabled and removed.
if (!initialized_) {
return EfficiencyMode::kNormal;
}
// It's possible for this function to be called during shutdown, after
// UserPerformanceTuningManager is destroyed. Do not access UPTM directly from
// here.
bool high_efficiency_enabled =
local_state_->GetInteger(kHighEfficiencyModeState) !=
static_cast<int>(HighEfficiencyModeState::kDisabled);
if (high_efficiency_enabled && battery_saver_enabled_) {
return EfficiencyMode::kBoth;
}
if (high_efficiency_enabled) {
return EfficiencyMode::kHighEfficiency;
}
if (battery_saver_enabled_) {
return EfficiencyMode::kBatterySaver;
}
return EfficiencyMode::kNormal;
}
void MetricsProvider::RecordAvailableMemoryMetrics() {
auto available_bytes = base::SysInfo::AmountOfAvailablePhysicalMemory();
auto total_bytes = base::SysInfo::AmountOfPhysicalMemory();
base::UmaHistogramMemoryLargeMB("Memory.Experimental.AvailableMemoryMB",
available_bytes / kBytesPerMb);
base::UmaHistogramPercentage("Memory.Experimental.AvailableMemoryPercent",
available_bytes * 100 / total_bytes);
#if BUILDFLAG(IS_MAC)
base::SystemMemoryInfoKB info;
if (base::GetSystemMemoryInfo(&info)) {
base::UmaHistogramMemoryLargeMB(
"Memory.Experimental.MacFileBackedMemoryMB2",
info.file_backed / kKilobytesPerMb);
// `info.file_backed` is in kb, so multiply it by 1024 to get the amount of
// bytes
base::UmaHistogramPercentage(
"Memory.Experimental.MacAvailableMemoryPercentFreePageCache2",
(available_bytes + (info.file_backed * 1024)) * 100 / total_bytes);
}
#endif
}
} // namespace performance_manager