mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
3 Commits
main
...
nikwen/hea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
789ae68cc4 | ||
|
|
a1638fd996 | ||
|
|
f4f30bfa86 |
5
BUILD.gn
5
BUILD.gn
@@ -476,8 +476,12 @@ source_set("electron_lib") {
|
||||
"//components/certificate_transparency",
|
||||
"//components/compose:buildflags",
|
||||
"//components/embedder_support:user_agent",
|
||||
"//components/heap_profiling/in_process",
|
||||
"//components/heap_profiling/in_process:mojom",
|
||||
"//components/heap_profiling/multi_process",
|
||||
"//components/input",
|
||||
"//components/language/core/browser",
|
||||
"//components/memory_system",
|
||||
"//components/net_log",
|
||||
"//components/network_hints/browser",
|
||||
"//components/network_hints/common:mojo_bindings",
|
||||
@@ -490,6 +494,7 @@ source_set("electron_lib") {
|
||||
"//components/pref_registry",
|
||||
"//components/prefs",
|
||||
"//components/security_state/content",
|
||||
"//components/tracing:tracing_metrics",
|
||||
"//components/upload_list",
|
||||
"//components/user_prefs",
|
||||
"//components/viz/host",
|
||||
|
||||
@@ -432,6 +432,8 @@ filenames = {
|
||||
"shell/browser/media/media_capture_devices_dispatcher.h",
|
||||
"shell/browser/media/media_device_id_salt.cc",
|
||||
"shell/browser/media/media_device_id_salt.h",
|
||||
"shell/browser/metrics/electron_metrics_service_client.cc",
|
||||
"shell/browser/metrics/electron_metrics_service_client.h",
|
||||
"shell/browser/microtasks_runner.cc",
|
||||
"shell/browser/microtasks_runner.h",
|
||||
"shell/browser/native_window.cc",
|
||||
@@ -508,6 +510,10 @@ filenames = {
|
||||
"shell/browser/session_preferences.h",
|
||||
"shell/browser/special_storage_policy.cc",
|
||||
"shell/browser/special_storage_policy.h",
|
||||
"shell/browser/tracing/electron_background_tracing_metrics_provider.cc",
|
||||
"shell/browser/tracing/electron_background_tracing_metrics_provider.h",
|
||||
"shell/browser/tracing/electron_tracing_delegate.cc",
|
||||
"shell/browser/tracing/electron_tracing_delegate.h",
|
||||
"shell/browser/ui/accelerator_util.cc",
|
||||
"shell/browser/ui/accelerator_util.h",
|
||||
"shell/browser/ui/autofill_popup.cc",
|
||||
|
||||
@@ -11,11 +11,17 @@
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/extend.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/string_split.h"
|
||||
#include "components/heap_profiling/in_process/child_process_snapshot_controller.h"
|
||||
#include "components/heap_profiling/in_process/heap_profiler_controller.h"
|
||||
#include "components/heap_profiling/in_process/mojom/snapshot_controller.mojom.h"
|
||||
#include "components/services/heap_profiling/public/cpp/profiling_client.h"
|
||||
#include "content/public/common/buildflags.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "electron/fuses.h"
|
||||
#include "extensions/common/constants.h"
|
||||
#include "mojo/public/cpp/bindings/binder_map.h"
|
||||
#include "pdf/buildflags.h"
|
||||
#include "shell/common/options_switches.h"
|
||||
#include "shell/common/process_util.h"
|
||||
@@ -217,4 +223,31 @@ void ElectronContentClient::AddContentDecryptionModules(
|
||||
}
|
||||
}
|
||||
|
||||
// Mirrors |ChromeContentClient::ExposeInterfacesToBrowser|.
|
||||
void ElectronContentClient::ExposeInterfacesToBrowser(
|
||||
scoped_refptr<base::SequencedTaskRunner> io_task_runner,
|
||||
mojo::BinderMap* binders) {
|
||||
// Sets up the client side of the multi-process heap profiler service.
|
||||
binders->Add<heap_profiling::mojom::ProfilingClient>(
|
||||
[](mojo::PendingReceiver<heap_profiling::mojom::ProfilingClient>
|
||||
receiver) {
|
||||
static base::NoDestructor<heap_profiling::ProfilingClient>
|
||||
profiling_client;
|
||||
profiling_client->BindToInterface(std::move(receiver));
|
||||
},
|
||||
io_task_runner);
|
||||
|
||||
// Sets up the simplified in-process heap profiler, if it's enabled.
|
||||
const auto* heap_profiler_controller =
|
||||
heap_profiling::HeapProfilerController::GetInstance();
|
||||
if (heap_profiler_controller && heap_profiler_controller->IsEnabled()) {
|
||||
binders->Add<heap_profiling::mojom::SnapshotController>(
|
||||
&heap_profiling::ChildProcessSnapshotController::
|
||||
CreateSelfOwnedReceiver,
|
||||
// ChildProcessSnapshotController calls into HeapProfilerController,
|
||||
// which can only be accessed on this sequence.
|
||||
base::SequencedTaskRunner::GetCurrentDefault());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -33,6 +33,9 @@ class ElectronContentClient : public content::ContentClient {
|
||||
void AddContentDecryptionModules(
|
||||
std::vector<content::CdmInfo>* cdms,
|
||||
std::vector<media::CdmHostFilePath>* cdm_host_file_paths) override;
|
||||
void ExposeInterfacesToBrowser(
|
||||
scoped_refptr<base::SequencedTaskRunner> io_task_runner,
|
||||
mojo::BinderMap* binders) override;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -23,9 +23,13 @@
|
||||
#include "base/strings/cstring_view.h"
|
||||
#include "base/strings/string_number_conversions.cc"
|
||||
#include "base/strings/string_util_internal.h"
|
||||
#include "base/version_info/channel.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "chrome/common/profiler/process_type.h"
|
||||
#include "components/content_settings/core/common/content_settings_pattern.h"
|
||||
#include "components/memory_system/initializer.h"
|
||||
#include "components/memory_system/parameters.h"
|
||||
#include "content/public/app/initialize_mojo_core.h"
|
||||
#include "content/public/common/content_switches.h"
|
||||
#include "crypto/hash.h"
|
||||
@@ -343,6 +347,39 @@ std::optional<int> ElectronMainDelegate::PreBrowserMain() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int> ElectronMainDelegate::PostEarlyInitialization(
|
||||
InvokedIn invoked_in) {
|
||||
// Start memory observation as early as possible so it can start recording
|
||||
// memory allocations. This includes heap profiling.
|
||||
InitializeMemorySystem();
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Mirrors |ChromeMainDelegate::InitializeMemorySystem|.
|
||||
void ElectronMainDelegate::InitializeMemorySystem() {
|
||||
const base::CommandLine* const command_line =
|
||||
base::CommandLine::ForCurrentProcess();
|
||||
const std::string process_type =
|
||||
command_line->GetSwitchValueASCII(::switches::kProcessType);
|
||||
const bool is_browser_process = process_type.empty();
|
||||
const memory_system::DispatcherParameters::AllocationTraceRecorderInclusion
|
||||
allocation_recorder_inclusion =
|
||||
is_browser_process ? memory_system::DispatcherParameters::
|
||||
AllocationTraceRecorderInclusion::kDynamic
|
||||
: memory_system::DispatcherParameters::
|
||||
AllocationTraceRecorderInclusion::kIgnore;
|
||||
|
||||
memory_system::Initializer()
|
||||
.SetGwpAsanParameters(is_browser_process, process_type)
|
||||
.SetProfilingClientParameters(version_info::Channel::UNKNOWN,
|
||||
GetProfilerProcessType(*command_line))
|
||||
.SetDispatcherParameters(memory_system::DispatcherParameters::
|
||||
PoissonAllocationSamplerInclusion::kEnforce,
|
||||
allocation_recorder_inclusion, process_type)
|
||||
.Initialize(memory_system_);
|
||||
}
|
||||
|
||||
std::string_view ElectronMainDelegate::GetBrowserV8SnapshotFilename() {
|
||||
bool load_browser_process_specific_v8_snapshot =
|
||||
IsBrowserProcess() &&
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "components/memory_system/memory_system.h"
|
||||
#include "content/public/app/content_main_delegate.h"
|
||||
|
||||
namespace content {
|
||||
@@ -47,6 +48,7 @@ class ElectronMainDelegate : public content::ContentMainDelegate {
|
||||
void PreSandboxStartup() override;
|
||||
void SandboxInitialized(const std::string& process_type) override;
|
||||
std::optional<int> PreBrowserMain() override;
|
||||
std::optional<int> PostEarlyInitialization(InvokedIn invoked_in) override;
|
||||
content::ContentClient* CreateContentClient() override;
|
||||
content::ContentBrowserClient* CreateContentBrowserClient() override;
|
||||
content::ContentGpuClient* CreateContentGpuClient() override;
|
||||
@@ -63,6 +65,8 @@ class ElectronMainDelegate : public content::ContentMainDelegate {
|
||||
void ZygoteForked() override;
|
||||
#endif
|
||||
|
||||
void InitializeMemorySystem();
|
||||
|
||||
private:
|
||||
std::unique_ptr<content::ContentBrowserClient> browser_client_;
|
||||
std::unique_ptr<content::ContentClient> content_client_;
|
||||
@@ -70,6 +74,8 @@ class ElectronMainDelegate : public content::ContentMainDelegate {
|
||||
std::unique_ptr<content::ContentRendererClient> renderer_client_;
|
||||
std::unique_ptr<content::ContentUtilityClient> utility_client_;
|
||||
std::unique_ptr<tracing::TracingSamplerProfiler> tracing_sampler_profiler_;
|
||||
|
||||
memory_system::MemorySystem memory_system_;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "net/proxy_resolution/proxy_config_with_annotation.h"
|
||||
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
|
||||
#include "services/network/public/cpp/network_switches.h"
|
||||
#include "shell/browser/metrics/electron_metrics_service_client.h"
|
||||
#include "shell/browser/net/resolve_proxy_helper.h"
|
||||
#include "shell/common/electron_paths.h"
|
||||
#include "shell/common/thread_restrictions.h"
|
||||
@@ -139,6 +140,8 @@ void BrowserProcessImpl::PostEarlyInitialization() {
|
||||
PrefServiceFactory prefs_factory;
|
||||
auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
|
||||
PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
|
||||
electron::ElectronMetricsServiceClient::RegisterMetricsPrefs(
|
||||
pref_registry.get());
|
||||
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
OSCrypt::RegisterLocalPrefs(pref_registry.get());
|
||||
@@ -176,6 +179,10 @@ void BrowserProcessImpl::PreCreateThreads() {
|
||||
// this can be created on first use.
|
||||
if (!SystemNetworkContextManager::GetInstance())
|
||||
SystemNetworkContextManager::CreateInstance(local_state_.get());
|
||||
|
||||
// Needs to be called here as per
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/chrome_browser_main.cc;l=1385-1389;drc=c3bda003554dad21313fb24b7a4f3e1aae6102d9.
|
||||
CreateMetricsServiceClient();
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::PreMainMessageLoopRun() {
|
||||
@@ -201,7 +208,10 @@ BrowserProcessImpl::GetMetricsServicesManager() {
|
||||
}
|
||||
|
||||
metrics::MetricsService* BrowserProcessImpl::metrics_service() {
|
||||
return nullptr;
|
||||
if (!metrics_service_client_) {
|
||||
return nullptr;
|
||||
}
|
||||
return metrics_service_client_->GetMetricsService();
|
||||
}
|
||||
|
||||
ProfileManager* BrowserProcessImpl::profile_manager() {
|
||||
@@ -508,3 +518,8 @@ void BrowserProcessImpl::CreateOSCryptAsync() {
|
||||
os_crypt_async_ =
|
||||
std::make_unique<os_crypt_async::OSCryptAsync>(std::move(providers));
|
||||
}
|
||||
|
||||
void BrowserProcessImpl::CreateMetricsServiceClient() {
|
||||
metrics_service_client_ =
|
||||
std::make_unique<electron::ElectronMetricsServiceClient>();
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ namespace printing {
|
||||
class PrintJobManager;
|
||||
}
|
||||
|
||||
namespace metrics {
|
||||
class MetricsServiceClient;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
class ResolveProxyHelper;
|
||||
}
|
||||
@@ -145,6 +149,7 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
private:
|
||||
void CreateNetworkQualityObserver();
|
||||
void CreateOSCryptAsync();
|
||||
void CreateMetricsServiceClient();
|
||||
network::NetworkQualityTracker* GetNetworkQualityTracker();
|
||||
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -166,6 +171,7 @@ class BrowserProcessImpl : public BrowserProcess {
|
||||
network_quality_observer_;
|
||||
std::unique_ptr<supervised_user::DeviceParentalControls>
|
||||
device_parental_controls_;
|
||||
std::unique_ptr<metrics::MetricsServiceClient> metrics_service_client_;
|
||||
|
||||
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_async_;
|
||||
};
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
#include "shell/browser/protocol_registry.h"
|
||||
#include "shell/browser/serial/electron_serial_delegate.h"
|
||||
#include "shell/browser/session_preferences.h"
|
||||
#include "shell/browser/tracing/electron_tracing_delegate.h"
|
||||
#include "shell/browser/ui/devtools_manager_delegate.h"
|
||||
#include "shell/browser/usb/electron_usb_delegate.h"
|
||||
#include "shell/browser/web_contents_permission_helper.h"
|
||||
@@ -1056,6 +1057,11 @@ std::string ElectronBrowserClient::GetProduct() {
|
||||
return "Chrome/" CHROME_VERSION_STRING;
|
||||
}
|
||||
|
||||
std::unique_ptr<content::TracingDelegate>
|
||||
ElectronBrowserClient::CreateTracingDelegate() {
|
||||
return std::make_unique<ElectronTracingDelegate>();
|
||||
}
|
||||
|
||||
std::string ElectronBrowserClient::GetUserAgent() {
|
||||
if (user_agent_override_.empty())
|
||||
return GetApplicationUserAgent();
|
||||
|
||||
@@ -218,6 +218,7 @@ class ElectronBrowserClient : public content::ContentBrowserClient,
|
||||
network::mojom::NetworkService* network_service) override;
|
||||
std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
|
||||
std::string GetProduct() override;
|
||||
std::unique_ptr<content::TracingDelegate> CreateTracingDelegate() override;
|
||||
mojo::PendingRemote<network::mojom::URLLoaderFactory>
|
||||
CreateNonNetworkNavigationURLLoaderFactory(
|
||||
const std::string& scheme,
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
#include "chrome/browser/icon_manager.h"
|
||||
#include "chrome/browser/ui/color/chrome_color_mixers.h"
|
||||
#include "chrome/common/chrome_switches.h"
|
||||
#include "components/heap_profiling/multi_process/client_connection_manager.h"
|
||||
#include "components/heap_profiling/multi_process/supervisor.h"
|
||||
#include "components/os_crypt/sync/key_storage_config_linux.h"
|
||||
#include "components/os_crypt/sync/key_storage_util_linux.h"
|
||||
#include "components/os_crypt/sync/os_crypt.h"
|
||||
#include "components/password_manager/core/browser/password_manager_switches.h" // nogncheck
|
||||
#include "components/services/heap_profiling/public/cpp/settings.h"
|
||||
#include "content/browser/browser_main_loop.h" // nogncheck
|
||||
#include "content/public/browser/browser_child_process_host_delegate.h"
|
||||
#include "content/public/browser/browser_child_process_host_iterator.h"
|
||||
@@ -173,6 +176,31 @@ std::u16string MediaStringProvider(media::MessageId id) {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<heap_profiling::ClientConnectionManager>
|
||||
CreateClientConnectionManager(
|
||||
base::WeakPtr<heap_profiling::Controller> controller_weak_ptr,
|
||||
heap_profiling::Mode mode) {
|
||||
return std::make_unique<heap_profiling::ClientConnectionManager>(
|
||||
controller_weak_ptr, mode);
|
||||
}
|
||||
|
||||
// Mirrors |ChromeBrowserMainExtraPartsProfiling::PostCreateThreads|.
|
||||
void InitializeHeapProfiling() {
|
||||
heap_profiling::Supervisor::GetInstance()
|
||||
->SetClientConnectionManagerConstructor(&CreateClientConnectionManager);
|
||||
|
||||
#if !defined(ADDRESS_SANITIZER)
|
||||
// Memory sanitizers are using large memory shadow to keep track of memory
|
||||
// state. Using memlog and memory sanitizers at the same time is slowing down
|
||||
// user experience, causing the browser to be barely responsive. In theory,
|
||||
// memlog and memory sanitizers are compatible and can run at the same time.
|
||||
heap_profiling::Mode mode = heap_profiling::GetModeForStartup();
|
||||
if (mode != heap_profiling::Mode::kNone) {
|
||||
heap_profiling::Supervisor::GetInstance()->Start(base::OnceClosure());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
@@ -376,6 +404,8 @@ int ElectronBrowserMainParts::PreCreateThreads() {
|
||||
}
|
||||
|
||||
void ElectronBrowserMainParts::PostCreateThreads() {
|
||||
InitializeHeapProfiling();
|
||||
|
||||
content::GetIOThreadTaskRunner({})->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&tracing::TracingSamplerProfiler::CreateOnChildThread));
|
||||
|
||||
131
shell/browser/metrics/electron_metrics_service_client.cc
Normal file
131
shell/browser/metrics/electron_metrics_service_client.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/metrics/electron_metrics_service_client.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/version_info/channel.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/common/chrome_paths.h"
|
||||
#include "components/metrics/metrics_service.h"
|
||||
#include "components/metrics/metrics_state_manager.h"
|
||||
#include "components/metrics/net/cellular_logic_helper.h"
|
||||
#include "components/metrics/net/net_metrics_log_uploader.h"
|
||||
#include "components/metrics/version_utils.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "components/variations/synthetic_trial_registry.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "shell/browser/tracing/electron_background_tracing_metrics_provider.h"
|
||||
#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
ElectronMetricsServiceClient::ElectronMetricsServiceClient() {
|
||||
PrefService* local_state = g_browser_process->local_state();
|
||||
|
||||
base::FilePath user_data_dir;
|
||||
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
|
||||
|
||||
synthetic_trial_registry_ =
|
||||
std::make_unique<variations::SyntheticTrialRegistry>();
|
||||
|
||||
metrics_state_manager_ = metrics::MetricsStateManager::Create(
|
||||
local_state, this, std::wstring(), user_data_dir,
|
||||
metrics::StartupVisibility::kUnknown);
|
||||
|
||||
metrics_service_ = std::make_unique<metrics::MetricsService>(
|
||||
metrics_state_manager_.get(), this, local_state);
|
||||
|
||||
RegisterMetricsServiceProviders();
|
||||
}
|
||||
|
||||
ElectronMetricsServiceClient::~ElectronMetricsServiceClient() = default;
|
||||
|
||||
// static
|
||||
void ElectronMetricsServiceClient::RegisterMetricsPrefs(
|
||||
PrefRegistrySimple* registry) {
|
||||
metrics::MetricsService::RegisterPrefs(registry);
|
||||
}
|
||||
|
||||
variations::SyntheticTrialRegistry*
|
||||
ElectronMetricsServiceClient::GetSyntheticTrialRegistry() {
|
||||
return synthetic_trial_registry_.get();
|
||||
}
|
||||
|
||||
metrics::MetricsService* ElectronMetricsServiceClient::GetMetricsService() {
|
||||
return metrics_service_.get();
|
||||
}
|
||||
|
||||
void ElectronMetricsServiceClient::SetMetricsClientId(
|
||||
const std::string& client_id) {}
|
||||
|
||||
int32_t ElectronMetricsServiceClient::GetProduct() {
|
||||
return metrics::ChromeUserMetricsExtension::CHROME;
|
||||
}
|
||||
|
||||
std::string ElectronMetricsServiceClient::GetApplicationLocale() {
|
||||
return g_browser_process ? g_browser_process->GetApplicationLocale()
|
||||
: std::string();
|
||||
}
|
||||
|
||||
const network_time::NetworkTimeTracker*
|
||||
ElectronMetricsServiceClient::GetNetworkTimeTracker() {
|
||||
return g_browser_process ? g_browser_process->network_time_tracker()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
bool ElectronMetricsServiceClient::GetBrand(std::string* brand_code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
metrics::SystemProfileProto::Channel
|
||||
ElectronMetricsServiceClient::GetChannel() {
|
||||
return metrics::AsProtobufChannel(version_info::Channel::UNKNOWN);
|
||||
}
|
||||
|
||||
bool ElectronMetricsServiceClient::IsExtendedStableChannel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string ElectronMetricsServiceClient::GetVersionString() {
|
||||
return metrics::GetVersionString();
|
||||
}
|
||||
|
||||
void ElectronMetricsServiceClient::CollectFinalMetricsForLog(
|
||||
base::OnceClosure done_callback) {
|
||||
if (done_callback) {
|
||||
std::move(done_callback).Run();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<metrics::MetricsLogUploader>
|
||||
ElectronMetricsServiceClient::CreateUploader(
|
||||
const GURL& server_url,
|
||||
const GURL& insecure_server_url,
|
||||
std::string_view mime_type,
|
||||
metrics::MetricsLogUploader::MetricServiceType service_type,
|
||||
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
|
||||
return std::make_unique<metrics::NetMetricsLogUploader>(
|
||||
g_browser_process->shared_url_loader_factory(), server_url,
|
||||
insecure_server_url, mime_type, service_type, on_upload_complete);
|
||||
}
|
||||
|
||||
base::TimeDelta ElectronMetricsServiceClient::GetStandardUploadInterval() {
|
||||
return metrics::GetUploadInterval(metrics::ShouldUseCellularUploadInterval());
|
||||
}
|
||||
|
||||
bool ElectronMetricsServiceClient::IsConsentGiven() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ElectronMetricsServiceClient::RegisterMetricsServiceProviders() {
|
||||
metrics_service_->RegisterMetricsProvider(
|
||||
std::make_unique<ElectronBackgroundTracingMetricsProvider>());
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
71
shell/browser/metrics/electron_metrics_service_client.h
Normal file
71
shell/browser/metrics/electron_metrics_service_client.h
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_METRICS_ELECTRON_METRICS_SERVICE_CLIENT_H_
|
||||
#define ELECTRON_SHELL_BROWSER_METRICS_ELECTRON_METRICS_SERVICE_CLIENT_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "components/metrics/enabled_state_provider.h"
|
||||
#include "components/metrics/metrics_service_client.h"
|
||||
|
||||
namespace metrics {
|
||||
class MetricsService;
|
||||
class MetricsStateManager;
|
||||
} // namespace metrics
|
||||
|
||||
namespace variations {
|
||||
class SyntheticTrialRegistry;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronMetricsServiceClient : public metrics::MetricsServiceClient,
|
||||
public metrics::EnabledStateProvider {
|
||||
public:
|
||||
ElectronMetricsServiceClient();
|
||||
|
||||
ElectronMetricsServiceClient(const ElectronMetricsServiceClient&) = delete;
|
||||
ElectronMetricsServiceClient& operator=(const ElectronMetricsServiceClient&) =
|
||||
delete;
|
||||
|
||||
~ElectronMetricsServiceClient() override;
|
||||
|
||||
static void RegisterMetricsPrefs(PrefRegistrySimple* registry);
|
||||
|
||||
// metrics::MetricsServiceClient:
|
||||
variations::SyntheticTrialRegistry* GetSyntheticTrialRegistry() override;
|
||||
metrics::MetricsService* GetMetricsService() override;
|
||||
void SetMetricsClientId(const std::string& client_id) override;
|
||||
int32_t GetProduct() override;
|
||||
std::string GetApplicationLocale() override;
|
||||
const network_time::NetworkTimeTracker* GetNetworkTimeTracker() override;
|
||||
bool GetBrand(std::string* brand_code) override;
|
||||
metrics::SystemProfileProto::Channel GetChannel() override;
|
||||
bool IsExtendedStableChannel() override;
|
||||
std::string GetVersionString() override;
|
||||
void CollectFinalMetricsForLog(base::OnceClosure done_callback) override;
|
||||
std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
|
||||
const GURL& server_url,
|
||||
const GURL& insecure_server_url,
|
||||
std::string_view mime_type,
|
||||
metrics::MetricsLogUploader::MetricServiceType service_type,
|
||||
const metrics::MetricsLogUploader::UploadCallback& on_upload_complete)
|
||||
override;
|
||||
base::TimeDelta GetStandardUploadInterval() override;
|
||||
|
||||
// metrics::EnabledStateProvider:
|
||||
bool IsConsentGiven() const override;
|
||||
|
||||
private:
|
||||
void RegisterMetricsServiceProviders();
|
||||
|
||||
std::unique_ptr<variations::SyntheticTrialRegistry> synthetic_trial_registry_;
|
||||
std::unique_ptr<metrics::MetricsStateManager> metrics_state_manager_;
|
||||
std::unique_ptr<metrics::MetricsService> metrics_service_;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_METRICS_ELECTRON_METRICS_SERVICE_CLIENT_H_
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/tracing/electron_background_tracing_metrics_provider.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/version_info/channel.h"
|
||||
#include "components/metrics/metrics_log.h"
|
||||
#include "components/metrics/version_utils.h"
|
||||
#include "shell/browser/electron_browser_client.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
ElectronBackgroundTracingMetricsProvider::
|
||||
ElectronBackgroundTracingMetricsProvider() = default;
|
||||
|
||||
ElectronBackgroundTracingMetricsProvider::
|
||||
~ElectronBackgroundTracingMetricsProvider() = default;
|
||||
|
||||
void ElectronBackgroundTracingMetricsProvider::RecordCoreSystemProfileMetrics(
|
||||
metrics::SystemProfileProto& system_profile_proto) {
|
||||
auto* browser_client = ElectronBrowserClient::Get();
|
||||
const std::string application_locale =
|
||||
browser_client ? browser_client->GetApplicationLocale() : std::string();
|
||||
|
||||
metrics::MetricsLog::RecordCoreSystemProfile(
|
||||
metrics::GetVersionString(),
|
||||
metrics::AsProtobufChannel(version_info::Channel::UNKNOWN), false,
|
||||
application_locale, std::string(), &system_profile_proto);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
|
||||
#define ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
|
||||
|
||||
#include "components/tracing/common/background_tracing_metrics_provider.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronBackgroundTracingMetricsProvider
|
||||
: public tracing::BackgroundTracingMetricsProvider {
|
||||
public:
|
||||
ElectronBackgroundTracingMetricsProvider();
|
||||
|
||||
ElectronBackgroundTracingMetricsProvider(
|
||||
const ElectronBackgroundTracingMetricsProvider&) = delete;
|
||||
ElectronBackgroundTracingMetricsProvider& operator=(
|
||||
const ElectronBackgroundTracingMetricsProvider&) = delete;
|
||||
|
||||
~ElectronBackgroundTracingMetricsProvider() override;
|
||||
|
||||
// metrics::MetricsProvider:
|
||||
void RecordCoreSystemProfileMetrics(
|
||||
metrics::SystemProfileProto& system_profile_proto) override;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_BACKGROUND_TRACING_METRICS_PROVIDER_H_
|
||||
39
shell/browser/tracing/electron_tracing_delegate.cc
Normal file
39
shell/browser/tracing/electron_tracing_delegate.cc
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/tracing/electron_tracing_delegate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/functional/bind.h"
|
||||
#include "components/tracing/common/background_tracing_metrics_provider.h"
|
||||
#include "components/tracing/common/system_profile_metadata_recorder.h"
|
||||
#include "third_party/metrics_proto/system_profile.pb.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
ElectronTracingDelegate::ElectronTracingDelegate() = default;
|
||||
ElectronTracingDelegate::~ElectronTracingDelegate() = default;
|
||||
|
||||
// Mirrors |ChromeTracingDelegate::RecordSerializedSystemProfileMetrics|.
|
||||
std::string ElectronTracingDelegate::RecordSerializedSystemProfileMetrics()
|
||||
const {
|
||||
metrics::SystemProfileProto system_profile_proto;
|
||||
auto recorder = tracing::BackgroundTracingMetricsProvider::
|
||||
GetSystemProfileMetricsRecorder();
|
||||
if (!recorder) {
|
||||
return std::string();
|
||||
}
|
||||
recorder.Run(system_profile_proto);
|
||||
std::string serialized_system_profile;
|
||||
system_profile_proto.SerializeToString(&serialized_system_profile);
|
||||
return serialized_system_profile;
|
||||
}
|
||||
|
||||
tracing::MetadataDataSource::BundleRecorder
|
||||
ElectronTracingDelegate::CreateSystemProfileMetadataRecorder() const {
|
||||
return base::BindRepeating(&tracing::RecordSystemProfileMetadata);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
30
shell/browser/tracing/electron_tracing_delegate.h
Normal file
30
shell/browser/tracing/electron_tracing_delegate.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2026 Niklas Wenzel
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_TRACING_DELEGATE_H_
|
||||
#define ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_TRACING_DELEGATE_H_
|
||||
|
||||
#include "content/public/browser/tracing_delegate.h"
|
||||
#include "services/tracing/public/cpp/perfetto/metadata_data_source.h"
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronTracingDelegate : public content::TracingDelegate {
|
||||
public:
|
||||
ElectronTracingDelegate();
|
||||
|
||||
ElectronTracingDelegate(const ElectronTracingDelegate&) = delete;
|
||||
ElectronTracingDelegate& operator=(const ElectronTracingDelegate&) = delete;
|
||||
|
||||
~ElectronTracingDelegate() override;
|
||||
|
||||
// content::TracingDelegate:
|
||||
std::string RecordSerializedSystemProfileMetrics() const override;
|
||||
tracing::MetadataDataSource::BundleRecorder
|
||||
CreateSystemProfileMetadataRecorder() const override;
|
||||
};
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_TRACING_ELECTRON_TRACING_DELEGATE_H_
|
||||
@@ -2,11 +2,14 @@ import { app, contentTracing, TraceConfig, TraceCategoriesAndOptions } from 'ele
|
||||
|
||||
import { expect } from 'chai';
|
||||
|
||||
import { once } from 'node:events';
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
|
||||
import { ifdescribe } from './lib/spec-helpers';
|
||||
import { ifdescribe, ifit, startRemoteControlApp } from './lib/spec-helpers';
|
||||
|
||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
// FIXME: The tests are skipped on linux arm/arm64
|
||||
ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== 'linux'))('contentTracing', () => {
|
||||
@@ -184,5 +187,137 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
|
||||
const parsed = JSON.parse(data);
|
||||
expect(parsed.traceEvents.some((x: any) => x.cat === 'disabled-by-default-v8.cpu_profiler' && x.name === 'ProfileChunk')).to.be.true();
|
||||
});
|
||||
|
||||
describe('memory-infra heap dumps', () => {
|
||||
const checkForHeapDumps = async (launchArgs: string[]) => {
|
||||
const rc = await startRemoteControlApp(launchArgs);
|
||||
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await rc.remotely(async (utilityProcessPath: string) => {
|
||||
const { contentTracing, BrowserWindow, utilityProcess } = require('electron');
|
||||
const { once } = require('node:events');
|
||||
const fs = require('node:fs');
|
||||
const process = require('node:process');
|
||||
const { setTimeout } = require('node:timers/promises');
|
||||
|
||||
const isEventWithNonEmptyHeapDumpForProcess = (event: any, pid: number) =>
|
||||
event.cat === 'disabled-by-default-memory-infra' &&
|
||||
event.name === 'periodic_interval' &&
|
||||
event.pid === pid &&
|
||||
event.args.dumps.level_of_detail === 'detailed' &&
|
||||
event.args.dumps.process_mmaps?.vm_regions.length > 0 &&
|
||||
Object.values(event.args.dumps.allocators).some((allocator: any) => allocator.attrs.size?.value !== "0") &&
|
||||
Object.values(event.args.dumps.heaps_v2.allocators).some((allocator: any) => allocator.counts.length > 0 && allocator.nodes.length > 0 && allocator.sizes.length > 0);
|
||||
|
||||
const hasNonEmptyHeapDumpForProcess = (parsedTrace: any, pid: number) =>
|
||||
parsedTrace.traceEvents.some((event: any) => isEventWithNonEmptyHeapDumpForProcess(event, pid));
|
||||
|
||||
const interval = 1000;
|
||||
await contentTracing.startRecording({
|
||||
included_categories: ["disabled-by-default-memory-infra"],
|
||||
excluded_categories: ["*"],
|
||||
memory_dump_config: {
|
||||
triggers: [
|
||||
{ mode: "detailed", periodic_interval_ms: interval },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// Launch a renderer process
|
||||
const window = new BrowserWindow({ show: false });
|
||||
await window.webContents.loadURL('about:blank');
|
||||
|
||||
// Launch a utility process
|
||||
const utility = utilityProcess.fork(utilityProcessPath);
|
||||
await once(utility, 'spawn');
|
||||
|
||||
// Collect heap dumps
|
||||
await setTimeout(2 * interval);
|
||||
|
||||
const path = await contentTracing.stopRecording();
|
||||
const data = fs.readFileSync(path, 'utf8');
|
||||
const parsed = JSON.parse(data);
|
||||
|
||||
const hasBrowserProcessHeapDump = hasNonEmptyHeapDumpForProcess(parsed, process.pid);
|
||||
const hasRendererProcessHeapDump = hasNonEmptyHeapDumpForProcess(parsed, window.webContents.getOSProcessId());
|
||||
const hasUtilityProcessHeapDump = hasNonEmptyHeapDumpForProcess(parsed, utility.pid);
|
||||
|
||||
global.setTimeout(() => require('electron').app.quit());
|
||||
|
||||
return {
|
||||
hasBrowserProcessHeapDump,
|
||||
hasRendererProcessHeapDump,
|
||||
hasUtilityProcessHeapDump
|
||||
};
|
||||
}, path.join(fixturesPath, 'api', 'content-tracing', 'utility.js'));
|
||||
|
||||
const [code] = await once(rc.process, 'exit');
|
||||
expect(code).to.equal(0);
|
||||
|
||||
return {
|
||||
hasBrowserProcessHeapDump,
|
||||
hasRendererProcessHeapDump,
|
||||
hasUtilityProcessHeapDump
|
||||
};
|
||||
};
|
||||
|
||||
it('are not included when launched without --memlog', async function () {
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await checkForHeapDumps([]);
|
||||
|
||||
expect(hasBrowserProcessHeapDump).to.be.false();
|
||||
expect(hasRendererProcessHeapDump).to.be.false();
|
||||
expect(hasUtilityProcessHeapDump).to.be.false();
|
||||
});
|
||||
|
||||
// We disable --memlog for ASAN builds
|
||||
ifit(!process.env.IS_ASAN)('are included for browser process when launched with --memlog=browser', async function () {
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await checkForHeapDumps(['--memlog=browser']);
|
||||
|
||||
expect(hasBrowserProcessHeapDump).to.be.true();
|
||||
expect(hasRendererProcessHeapDump).to.be.false();
|
||||
expect(hasUtilityProcessHeapDump).to.be.false();
|
||||
});
|
||||
|
||||
ifit(!process.env.IS_ASAN)('are included for renderer processes when launched with --memlog=all-renderers', async function () {
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await checkForHeapDumps(['--memlog=all-renderers']);
|
||||
|
||||
expect(hasBrowserProcessHeapDump).to.be.false();
|
||||
expect(hasRendererProcessHeapDump).to.be.true();
|
||||
expect(hasUtilityProcessHeapDump).to.be.false();
|
||||
});
|
||||
|
||||
ifit(!process.env.IS_ASAN)('are included for utility processes when launched with --memlog=all-utilities', async function () {
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await checkForHeapDumps(['--memlog=all-utilities']);
|
||||
|
||||
expect(hasBrowserProcessHeapDump).to.be.false();
|
||||
expect(hasRendererProcessHeapDump).to.be.false();
|
||||
expect(hasUtilityProcessHeapDump).to.be.true();
|
||||
});
|
||||
|
||||
ifit(!process.env.IS_ASAN)('are included for browser, renderer, and utility processes when launched with --memlog=all', async function () {
|
||||
const { hasBrowserProcessHeapDump, hasRendererProcessHeapDump, hasUtilityProcessHeapDump } = await checkForHeapDumps(['--memlog=all']);
|
||||
|
||||
expect(hasBrowserProcessHeapDump).to.be.true();
|
||||
expect(hasRendererProcessHeapDump).to.be.true();
|
||||
expect(hasUtilityProcessHeapDump).to.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('trace metadata', () => {
|
||||
// These are necessary to be able to symbolicate heap dumps using third_party/catapult/tracing/bin/symbolize_trace (see https://github.com/electron/electron/pull/50826).
|
||||
it('includes product version and OS arch metadata in JSON output', async () => {
|
||||
const config = {
|
||||
excluded_categories: ['*']
|
||||
};
|
||||
await record(config, outputFilePath);
|
||||
|
||||
const content = fs.readFileSync(outputFilePath).toString();
|
||||
const parsed = JSON.parse(content);
|
||||
|
||||
expect(parsed.metadata).to.be.an('object');
|
||||
expect(parsed.metadata['product-version']).to.be.a('string');
|
||||
expect(parsed.metadata['product-version'].startsWith(process.versions.chrome)).to.be.true();
|
||||
expect(parsed.metadata['os-arch']).to.equal(process.arch);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
3
spec/fixtures/api/content-tracing/utility.js
vendored
Normal file
3
spec/fixtures/api/content-tracing/utility.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
setInterval(() => {
|
||||
new Array(1000000).fill(0);
|
||||
}, 100);
|
||||
Reference in New Issue
Block a user