diff --git a/lib/browser/rpc-server.ts b/lib/browser/rpc-server.ts index affa21a19d64..d8a80802060b 100644 --- a/lib/browser/rpc-server.ts +++ b/lib/browser/rpc-server.ts @@ -17,6 +17,10 @@ ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_LAST_WEB_PREFERENCES, function ( return event.sender.getLastWebPreferences(); }); +ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO, function (event) { + return event.sender._getProcessMemoryInfo(); +}); + // Methods not listed in this set are called directly in the renderer process. const allowedClipboardMethods = (() => { switch (process.platform) { diff --git a/lib/common/ipc-messages.ts b/lib/common/ipc-messages.ts index 5e626a3dfdf8..659b758ca976 100644 --- a/lib/common/ipc-messages.ts +++ b/lib/common/ipc-messages.ts @@ -4,6 +4,7 @@ export const enum IPC_MESSAGES { BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR', BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD', BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE', + BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO', GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE', diff --git a/lib/renderer/init.ts b/lib/renderer/init.ts index acb9ef203129..915cc8251114 100644 --- a/lib/renderer/init.ts +++ b/lib/renderer/init.ts @@ -59,6 +59,10 @@ v8Util.setHiddenValue(global, 'ipcNative', { } }); +process.getProcessMemoryInfo = () => { + return ipcRendererInternal.invoke(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO); +}; + // Use electron module after everything is ready. const { webFrameInit } = require('@electron/internal/renderer/web-frame-init') as typeof webFrameInitModule; webFrameInit(); diff --git a/lib/sandboxed_renderer/init.ts b/lib/sandboxed_renderer/init.ts index a91a6b6692a5..2411b6def254 100644 --- a/lib/sandboxed_renderer/init.ts +++ b/lib/sandboxed_renderer/init.ts @@ -86,6 +86,10 @@ Object.assign(preloadProcess, processProps); Object.assign(process, binding.process); Object.assign(process, processProps); +process.getProcessMemoryInfo = preloadProcess.getProcessMemoryInfo = () => { + return ipcRendererInternal.invoke(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO); +}; + Object.defineProperty(preloadProcess, 'noDeprecation', { get () { return process.noDeprecation; diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index f8779ad012f1..2518b382a3fa 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -72,6 +72,7 @@ #include "ppapi/buildflags/buildflags.h" #include "printing/buildflags/buildflags.h" #include "printing/print_job_constants.h" +#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "shell/browser/api/electron_api_browser_window.h" #include "shell/browser/api/electron_api_debugger.h" @@ -99,6 +100,7 @@ #include "shell/browser/web_view_guest_delegate.h" #include "shell/browser/web_view_manager.h" #include "shell/common/api/electron_api_native_image.h" +#include "shell/common/api/electron_bindings.h" #include "shell/common/color_util.h" #include "shell/common/electron_constants.h" #include "shell/common/gin_converters/base_converter.h" @@ -3228,6 +3230,26 @@ void WebContents::SetImageAnimationPolicy(const std::string& new_policy) { web_contents()->OnWebPreferencesChanged(); } +v8::Local WebContents::GetProcessMemoryInfo(v8::Isolate* isolate) { + gin_helper::Promise promise(isolate); + v8::Local handle = promise.GetHandle(); + + auto* frame_host = web_contents()->GetMainFrame(); + if (!frame_host) { + promise.RejectWithErrorMessage("Failed to create memory dump"); + return handle; + } + + auto pid = frame_host->GetProcess()->GetProcess().Pid(); + v8::Global context(isolate, isolate->GetCurrentContext()); + memory_instrumentation::MemoryInstrumentation::GetInstance() + ->RequestGlobalDumpForPid( + pid, std::vector(), + base::BindOnce(&ElectronBindings::DidReceiveMemoryDump, + std::move(context), std::move(promise), pid)); + return handle; +} + v8::Local WebContents::TakeHeapSnapshot( v8::Isolate* isolate, const base::FilePath& file_path) { @@ -3853,6 +3875,7 @@ v8::Local WebContents::FillObjectTemplate( .SetMethod("takeHeapSnapshot", &WebContents::TakeHeapSnapshot) .SetMethod("setImageAnimationPolicy", &WebContents::SetImageAnimationPolicy) + .SetMethod("_getProcessMemoryInfo", &WebContents::GetProcessMemoryInfo) .SetProperty("id", &WebContents::ID) .SetProperty("session", &WebContents::Session) .SetProperty("hostWebContents", &WebContents::HostWebContents) diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index fc137ef6e2d1..ac1bbb49b86d 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -323,6 +323,7 @@ class WebContents : public gin::Wrappable, v8::Local TakeHeapSnapshot(v8::Isolate* isolate, const base::FilePath& file_path); + v8::Local GetProcessMemoryInfo(v8::Isolate* isolate); // Properties. int32_t ID() const { return id_; } diff --git a/shell/common/api/electron_bindings.cc b/shell/common/api/electron_bindings.cc index 7561c0c076e6..7bd3a57cae74 100644 --- a/shell/common/api/electron_bindings.cc +++ b/shell/common/api/electron_bindings.cc @@ -50,7 +50,9 @@ void ElectronBindings::BindProcess(v8::Isolate* isolate, process->SetMethod("getCreationTime", &GetCreationTime); process->SetMethod("getHeapStatistics", &GetHeapStatistics); process->SetMethod("getBlinkMemoryInfo", &GetBlinkMemoryInfo); - process->SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo); + if (gin_helper::Locker::IsBrowserProcess()) { + process->SetMethod("getProcessMemoryInfo", &GetProcessMemoryInfo); + } process->SetMethod("getSystemMemoryInfo", &GetSystemMemoryInfo); process->SetMethod("getSystemVersion", &base::SysInfo::OperatingSystemVersion); @@ -207,10 +209,11 @@ v8::Local ElectronBindings::GetSystemMemoryInfo( // static v8::Local ElectronBindings::GetProcessMemoryInfo( v8::Isolate* isolate) { + CHECK(gin_helper::Locker::IsBrowserProcess()); gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); - if (gin_helper::Locker::IsBrowserProcess() && !Browser::Get()->is_ready()) { + if (!Browser::Get()->is_ready()) { promise.RejectWithErrorMessage( "Memory Info is available only after app ready"); return handle; @@ -221,7 +224,8 @@ v8::Local ElectronBindings::GetProcessMemoryInfo( ->RequestGlobalDumpForPid( base::GetCurrentProcId(), std::vector(), base::BindOnce(&ElectronBindings::DidReceiveMemoryDump, - std::move(context), std::move(promise))); + std::move(context), std::move(promise), + base::GetCurrentProcId())); return handle; } @@ -242,6 +246,7 @@ v8::Local ElectronBindings::GetBlinkMemoryInfo( void ElectronBindings::DidReceiveMemoryDump( v8::Global context, gin_helper::Promise promise, + base::ProcessId target_pid, bool success, std::unique_ptr global_dump) { v8::Isolate* isolate = promise.isolate(); @@ -259,7 +264,7 @@ void ElectronBindings::DidReceiveMemoryDump( bool resolved = false; for (const memory_instrumentation::GlobalMemoryDump::ProcessDump& dump : global_dump->process_dumps()) { - if (base::GetCurrentProcId() == dump.pid()) { + if (target_pid == dump.pid()) { gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate); const auto& osdump = dump.os_dump(); #if defined(OS_LINUX) || defined(OS_WIN) diff --git a/shell/common/api/electron_bindings.h b/shell/common/api/electron_bindings.h index 2ea20c8ae774..6796183d8446 100644 --- a/shell/common/api/electron_bindings.h +++ b/shell/common/api/electron_bindings.h @@ -49,6 +49,13 @@ class ElectronBindings { static void Crash(); + static void DidReceiveMemoryDump( + v8::Global context, + gin_helper::Promise promise, + base::ProcessId target_pid, + bool success, + std::unique_ptr dump); + private: static void Hang(); static v8::Local GetHeapStatistics(v8::Isolate* isolate); @@ -67,12 +74,6 @@ class ElectronBindings { static void OnCallNextTick(uv_async_t* handle); - static void DidReceiveMemoryDump( - v8::Global context, - gin_helper::Promise promise, - bool success, - std::unique_ptr dump); - UvHandle call_next_tick_async_; std::list pending_next_ticks_; std::unique_ptr metrics_; diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 5d67e53e1630..ab5ea9b55a2a 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -58,6 +58,7 @@ declare namespace Electron { _loadURL(url: string, options: ElectronInternal.LoadURLOptions): void; getOwnerBrowserWindow(): Electron.BrowserWindow | null; getLastWebPreferences(): Electron.WebPreferences | null; + _getProcessMemoryInfo(): Electron.ProcessMemoryInfo; _getPreloadPaths(): string[]; equal(other: WebContents): boolean; browserWindowOptions: BrowserWindowConstructorOptions;