diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 115041d0082d..1024bb0c6ccb 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -34,12 +34,12 @@ #include "chrome/browser/icon_manager.h" #include "chrome/common/chrome_paths.h" #include "content/public/browser/browser_accessibility_state.h" +#include "content/public/browser/browser_child_process_host.h" #include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/common/content_switches.h" #include "media/audio/audio_manager.h" -#include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" #include "net/ssl/ssl_cert_request_info.h" #include "ui/base/l10n/l10n_util.h" @@ -337,6 +337,17 @@ namespace api { namespace { +class AppIdProcessIterator : public base::ProcessIterator { + public: + AppIdProcessIterator() : base::ProcessIterator(nullptr) {} + + protected: + bool IncludeEntry() override { + return (entry().parent_pid() == base::GetCurrentProcId() || + entry().pid() == base::GetCurrentProcId()); + } +}; + IconLoader::IconSize GetIconSizeByString(const std::string& size) { if (size == "small") { return IconLoader::IconSize::SMALL; @@ -912,6 +923,47 @@ void App::GetFileIcon(const base::FilePath& path, } } +std::vector App::GetAppMemoryInfo(v8::Isolate* isolate) { + AppIdProcessIterator process_iterator; + auto process_entry = process_iterator.NextProcessEntry(); + std::vector result; + + while (process_entry != nullptr) { + int64_t pid = process_entry->pid(); + auto process = base::Process::OpenWithExtraPrivileges(pid); + +#if defined(OS_MACOSX) + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics( + process.Handle(), content::BrowserChildProcessHost::GetPortProvider())); +#else + std::unique_ptr metrics( + base::ProcessMetrics::CreateProcessMetrics(process.Handle())); +#endif + + mate::Dictionary pid_dict = mate::Dictionary::CreateEmpty(isolate); + mate::Dictionary memory_dict = mate::Dictionary::CreateEmpty(isolate); + + memory_dict.Set("workingSetSize", + static_cast(metrics->GetWorkingSetSize() >> 10)); + memory_dict.Set("peakWorkingSetSize", + static_cast(metrics->GetPeakWorkingSetSize() >> 10)); + + size_t private_bytes, shared_bytes; + if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes)) { + memory_dict.Set("privateBytes", static_cast(private_bytes >> 10)); + memory_dict.Set("sharedBytes", static_cast(shared_bytes >> 10)); + } + + pid_dict.Set("memory", memory_dict); + pid_dict.Set("pid", pid); + result.push_back(pid_dict); + process_entry = process_iterator.NextProcessEntry(); + } + + return result; +} + // static mate::Handle App::Create(v8::Isolate* isolate) { return mate::CreateHandle(isolate, new App(isolate)); @@ -983,7 +1035,8 @@ void App::BuildPrototype( &App::IsAccessibilitySupportEnabled) .SetMethod("disableHardwareAcceleration", &App::DisableHardwareAcceleration) - .SetMethod("getFileIcon", &App::GetFileIcon); + .SetMethod("getFileIcon", &App::GetFileIcon) + .SetMethod("getAppMemoryInfo", &App::GetAppMemoryInfo); } } // namespace api diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index a87b88bc4642..9543e4b74b22 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -13,10 +13,12 @@ #include "atom/browser/browser.h" #include "atom/browser/browser_observer.h" #include "atom/common/native_mate_converters/callback.h" +#include "base/process/process_iterator.h" #include "base/task/cancelable_task_tracker.h" #include "chrome/browser/icon_manager.h" #include "chrome/browser/process_singleton.h" #include "content/public/browser/gpu_data_manager_observer.h" +#include "native_mate/dictionary.h" #include "native_mate/handle.h" #include "net/base/completion_callback.h" @@ -141,6 +143,8 @@ class App : public AtomBrowserClient::Delegate, void GetFileIcon(const base::FilePath& path, mate::Arguments* args); + std::vector GetAppMemoryInfo(v8::Isolate* isolate); + #if defined(OS_WIN) // Get the current Jump List settings. v8::Local GetJumpListSettings(); diff --git a/docs/api/app.md b/docs/api/app.md index e3160e9053f8..cf537474af24 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -760,6 +760,10 @@ Disables hardware acceleration for current app. This method can only be called before app is ready. +### `app.getAppMemoryInfo()` + +Returns [ProcessMemoryInfo[]](structures/process-memory-info.md): Array of `ProcessMemoryInfo` objects that correspond to memory usage statistics of all the processes associated with the app. + ### `app.setBadgeCount(count)` _Linux_ _macOS_ * `count` Integer diff --git a/docs/api/structures/memory-info.md b/docs/api/structures/memory-info.md new file mode 100644 index 000000000000..69c67f16cc82 --- /dev/null +++ b/docs/api/structures/memory-info.md @@ -0,0 +1,12 @@ +# MemoryInfo Object + +* `workingSetSize` Integer - Process id of the process. +* `workingSetSize` Integer - The amount of memory currently pinned to actual physical RAM. +* `peakWorkingSetSize` Integer - The maximum amount of memory that has ever been pinned + to actual physical RAM. +* `privateBytes` Integer - The amount of memory not shared by other processes, such as + JS heap or HTML content. +* `sharedBytes` Integer - The amount of memory shared between processes, typically + memory consumed by the Electron code itself + +Note that all statistics are reported in Kilobytes. \ No newline at end of file diff --git a/docs/api/structures/process-memory-info.md b/docs/api/structures/process-memory-info.md new file mode 100644 index 000000000000..68198f2d4540 --- /dev/null +++ b/docs/api/structures/process-memory-info.md @@ -0,0 +1,4 @@ +# ProcessMemoryInfo Object + +* `pid` Integer - Process id of the process. +* `memory` [MemoryInfo](memory-info.md) - Memory information of the process. diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 9a9b4334bceb..1bcc1a5c6223 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -533,4 +533,17 @@ describe('app module', function () { }) }) }) + + describe('getAppMemoryInfo() API', function () { + it('returns the process memory of all running electron processes', function () { + const appMemoryInfo = app.getAppMemoryInfo() + assert.ok(appMemoryInfo.length > 0, 'App memory info object is not > 0') + for (const {memory, pid} of appMemoryInfo) { + assert.ok(memory.workingSetSize > 0, 'working set size is not > 0') + assert.ok(memory.privateBytes > 0, 'private bytes is not > 0') + assert.ok(memory.sharedBytes > 0, 'shared bytes is not > 0') + assert.ok(pid > 0, 'pid is not > 0') + } + }) + }) })