#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "components/startup_metric_utils/browser/startup_metric_utils.h"
#include <stddef.h>
#include <stdint.h>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>
#include "base/command_line.h"
#include "base/dcheck_is_on.h"
#include "base/location.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/threading/scoped_thread_priority.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "components/privacy_sandbox/privacy_sandbox_attestations/privacy_sandbox_attestations_histograms.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include <winternl.h>
#include "base/win/win_util.h"
namespace {
typedef NTSTATUS(WINAPI* NtQuerySystemInformationPtr)(SYSTEM_INFORMATION_CLASS,
PVOID,
ULONG,
PULONG);
constexpr uint32_t kWarmStartHardFaultCountThreshold = 5;
constexpr uint32_t kColdStartHardFaultCountThreshold = 3500;
struct SYSTEM_PROCESS_INFORMATION_EX {
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER WorkingSetPrivateSize;
ULONG HardFaultCount;
BYTE Reserved1[36];
PVOID Reserved2[3];
HANDLE UniqueProcessId;
PVOID Reserved3;
ULONG HandleCount;
BYTE Reserved4[4];
PVOID Reserved5[11];
SIZE_T PeakPagefileUsage;
SIZE_T PrivatePageCount;
LARGE_INTEGER Reserved6[6];
};
}
#endif
namespace {
const char kProcessType[] = …;
enum StartupTemperature { … };
StartupTemperature g_startup_temperature = …;
template <typename T>
void UmaHistogramWithTemperature(
void (*histogram_function)(const std::string& name, T),
const std::string& histogram_basename,
T value) { … }
void UmaHistogramWithTraceAndTemperature(
void (*histogram_function)(const std::string& name, base::TimeDelta),
const char* histogram_basename,
base::TimeTicks begin_ticks,
base::TimeTicks end_ticks) { … }
}
namespace startup_metric_utils {
BrowserStartupMetricRecorder& GetBrowser() { … }
#if BUILDFLAG(IS_WIN)
std::optional<uint32_t>
BrowserStartupMetricRecorder::GetHardFaultCountForCurrentProcess() {
static const NtQuerySystemInformationPtr query_sys_info =
reinterpret_cast<NtQuerySystemInformationPtr>(::GetProcAddress(
GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation"));
if (query_sys_info == nullptr) {
return std::nullopt;
}
std::vector<uint8_t> buffer(32 * 1024);
constexpr int kMaxNumBufferResize = 2;
int num_buffer_resize = 0;
for (;;) {
ULONG return_length = 0;
const NTSTATUS status =
query_sys_info(SystemProcessInformation, buffer.data(),
static_cast<ULONG>(buffer.size()), &return_length);
if (NT_SUCCESS(status)) {
DCHECK_LE(return_length, buffer.size());
break;
}
if (return_length > buffer.size()) {
constexpr ULONG kMaxLength = 512 * 1024;
if (return_length >= kMaxLength) {
return std::nullopt;
}
if (num_buffer_resize < kMaxNumBufferResize) {
++num_buffer_resize;
buffer.resize(return_length);
continue;
}
}
DCHECK(return_length <= buffer.size() ||
num_buffer_resize >= kMaxNumBufferResize);
return std::nullopt;
}
const DWORD proc_id = ::GetCurrentProcessId();
size_t index = 0;
while (index < buffer.size()) {
DCHECK_LE(index + sizeof(SYSTEM_PROCESS_INFORMATION_EX), buffer.size());
SYSTEM_PROCESS_INFORMATION_EX* proc_info =
reinterpret_cast<SYSTEM_PROCESS_INFORMATION_EX*>(buffer.data() + index);
if (base::win::HandleToUint32(proc_info->UniqueProcessId) == proc_id) {
return proc_info->HardFaultCount;
}
if (proc_info->NextEntryOffset <= 0) {
return std::nullopt;
}
index += proc_info->NextEntryOffset;
}
return std::nullopt;
}
#endif
void BrowserStartupMetricRecorder::ResetSessionForTesting() { … }
bool BrowserStartupMetricRecorder::WasMainWindowStartupInterrupted() const { … }
void BrowserStartupMetricRecorder::SetNonBrowserUIDisplayed() { … }
void BrowserStartupMetricRecorder::SetBackgroundModeEnabled() { … }
void BrowserStartupMetricRecorder::RecordMessageLoopStartTicks(
base::TimeTicks ticks) { … }
base::TimeTicks BrowserStartupMetricRecorder::GetWebContentsStartTicks() const { … }
void BrowserStartupMetricRecorder::RecordBrowserMainMessageLoopStart(
base::TimeTicks ticks,
bool is_first_run) { … }
void BrowserStartupMetricRecorder::RecordBrowserMainLoopFirstIdle(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordBrowserWindowDisplay(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordBrowserWindowFirstPaintTicks(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordFirstWebContentsNonEmptyPaint(
base::TimeTicks now,
base::TimeTicks render_process_host_init_time) { … }
void BrowserStartupMetricRecorder::RecordFirstWebContentsMainNavigationStart(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordFirstWebContentsMainNavigationFinished(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordBrowserWindowFirstPaint(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordFirstRunSentinelCreation(
FirstRunSentinelCreationResult result) { … }
void BrowserStartupMetricRecorder::RecordHardFaultHistogram() { … }
bool BrowserStartupMetricRecorder::ShouldLogStartupHistogram() const { … }
#if BUILDFLAG(IS_CHROMEOS)
void BrowserStartupMetricRecorder::RecordWebContentsStartTime(
base::TimeTicks ticks) {
if (web_contents_start_ticks_.is_null()) {
web_contents_start_ticks_ = ticks;
DCHECK(!web_contents_start_ticks_.is_null());
}
}
#endif
void BrowserStartupMetricRecorder::RecordExternalStartupMetric(
const char* histogram_name,
base::TimeTicks completion_ticks,
bool set_non_browser_ui_displayed) { … }
void BrowserStartupMetricRecorder::RecordPrivacySandboxAttestationsFirstReady(
base::TimeTicks ticks) { … }
void BrowserStartupMetricRecorder::RecordPrivacySandboxAttestationFirstCheck(
base::TimeTicks ticks) { … }
}