/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __mozilla_ProcInfo_h #define __mozilla_ProcInfo_h #include #include #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/ChromeUtilsBinding.h" #include "mozilla/dom/ipc/IdType.h" #include "mozilla/HashTable.h" #include "mozilla/MozPromise.h" namespace mozilla { namespace ipc { class GeckoChildProcessHost; } /** * Return the number of milliseconds of CPU time used since process start. * * @return NS_OK on success. */ nsresult GetCpuTimeSinceProcessStartInMs(uint64_t* aResult); /** * Return the number of milliseconds of GPU time used since process start. * * @return NS_OK on success. */ nsresult GetGpuTimeSinceProcessStartInMs(uint64_t* aResult); // Process types. When updating this enum, please make sure to update // WebIDLProcType, ChromeUtils::RequestProcInfo and ProcTypeToWebIDL to // mirror the changes. enum class ProcType { // These must match the ones in RemoteType.h, and E10SUtils.sys.mjs Web, WebIsolated, File, Extension, PrivilegedAbout, PrivilegedMozilla, WebCOOPCOEP, WebServiceWorker, // the rest matches GeckoProcessTypes.h #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \ process_bin_type, procinfo_typename, \ webidl_typename, allcaps_name) \ procinfo_typename, #define SKIP_PROCESS_TYPE_CONTENT #ifndef MOZ_ENABLE_FORKSERVER # define SKIP_PROCESS_TYPE_FORKSERVER #endif // MOZ_ENABLE_FORKSERVER #include "mozilla/GeckoProcessTypes.h" #undef SKIP_PROCESS_TYPE_CONTENT #ifndef MOZ_ENABLE_FORKSERVER # undef SKIP_PROCESS_TYPE_FORKSERVER #endif // MOZ_ENABLE_FORKSERVER #undef GECKO_PROCESS_TYPE Preallocated, // Unknown type of process Unknown, Max = Unknown, }; using UtilityActorName = mozilla::dom::WebIDLUtilityActorName; // String that will be used e.g. to annotate crash reports nsCString GetUtilityActorName(const UtilityActorName aActorName); #ifdef XP_WIN int GetCpuFrequencyMHz(); #endif /* Get the CPU frequency to use to convert cycle time values to actual time. * @returns the TSC (Time Stamp Counter) frequency in MHz, or 0 if converting * cycle time values should not be attempted. */ int GetCycleTimeFrequencyMHz(); struct ThreadInfo { // Thread Id. base::ProcessId tid = 0; // Thread name, if any. nsString name; // CPU time in ns. uint64_t cpuTime = 0; // CPU time in cycles if available. uint64_t cpuCycleCount = 0; }; // Info on a DOM window. struct WindowInfo { explicit WindowInfo() : outerWindowId(0), documentURI(nullptr), documentTitle(u""_ns), isProcessRoot(false), isInProcess(false) {} WindowInfo(uint64_t aOuterWindowId, nsIURI* aDocumentURI, nsAString&& aDocumentTitle, bool aIsProcessRoot, bool aIsInProcess) : outerWindowId(aOuterWindowId), documentURI(aDocumentURI), documentTitle(std::move(aDocumentTitle)), isProcessRoot(aIsProcessRoot), isInProcess(aIsInProcess) {} // Internal window id. const uint64_t outerWindowId; // URI of the document. const nsCOMPtr documentURI; // Title of the document. const nsString documentTitle; // True if this is the toplevel window of the process. // Note that this may be an iframe from another process. const bool isProcessRoot; const bool isInProcess; }; // Info on a Utility process actor struct UtilityInfo { explicit UtilityInfo() : actorName(UtilityActorName::Unknown) {} explicit UtilityInfo(UtilityActorName aActorName) : actorName(aActorName) {} const UtilityActorName actorName; }; struct ProcInfo { // Process Id base::ProcessId pid = 0; // Child Id as defined by Firefox when a child process is created. dom::ContentParentId childId; // Process type ProcType type; // Origin, if any nsCString origin; // Memory size in bytes. uint64_t memory = 0; // CPU time in ns. uint64_t cpuTime = 0; uint64_t cpuCycleCount = 0; // Threads owned by this process. CopyableTArray threads; // DOM windows represented by this process. CopyableTArray windows; // Utility process actors, empty for non Utility process CopyableTArray utilityActors; }; typedef MozPromise, nsresult, true> ProcInfoPromise; /** * Data we need to request process info (e.g. CPU usage, memory usage) * from the operating system and populate the resulting `ProcInfo`. * * Note that this structure contains a mix of: * - low-level handles that we need to request low-level process info * (`aChildTask` on macOS, `aPid` on other platforms); and * - high-level data that we already acquired while looking for * `aPid`/`aChildTask` and that we will need further down the road. */ struct ProcInfoRequest { ProcInfoRequest(base::ProcessId aPid, ProcType aProcessType, const nsACString& aOrigin, nsTArray&& aWindowInfo, nsTArray&& aUtilityInfo, uint32_t aChildId = 0 #ifdef XP_DARWIN , mach_port_t aChildTask = 0 #endif // XP_DARWIN ) : pid(aPid), processType(aProcessType), origin(aOrigin), windowInfo(std::move(aWindowInfo)), utilityInfo(std::move(aUtilityInfo)), childId(aChildId) #ifdef XP_DARWIN , childTask(aChildTask) #endif // XP_DARWIN { } const base::ProcessId pid; const ProcType processType; const nsCString origin; const nsTArray windowInfo; const nsTArray utilityInfo; // If the process is a child, its child id, otherwise `0`. const int32_t childId; #ifdef XP_DARWIN const mach_port_t childTask; #endif // XP_DARWIN }; /** * Batch a request for low-level information on Gecko processes. * * # Request * * Argument `aRequests` is a list of processes, along with high-level data * we have already obtained on them and that we need to populate the * resulting array of `ProcInfo`. * * # Result * * This call succeeds (possibly with missing data, see below) unless we * cannot allocate memory. * * # Performance * * - This call is always executed on a background thread. * - This call does NOT wake up children processes. * - This function is sometimes observably slow to resolve, in particular * under Windows. * * # Error-handling and race conditions * * Requesting low-level information on a process and its threads is inherently * subject to race conditions. Typically, if a process or a thread is killed * while we're preparing to fetch information, we can easily end up with * system/lib calls that return failures. * * For this reason, this API assumes that errors when placing a system/lib call * are likely and normal. When some information cannot be obtained, the API will * simply skip over said information. * * Note that due to different choices by OSes, the exact information we skip may * vary across platforms. For instance, under Unix, failing to access the * threads of a process will cause us to skip all data on the process, while * under Windows, process information will be returned without thread * information. */ RefPtr GetProcInfo(nsTArray&& aRequests); /** * Synchronous version of GetProcInfo. */ ProcInfoPromise::ResolveOrRejectValue GetProcInfoSync( nsTArray&& aRequests); /** * Utility function: copy data from a `ProcInfo` and into either a * `ParentProcInfoDictionary` or a `ChildProcInfoDictionary`. */ template nsresult CopySysProcInfoToDOM(const ProcInfo& source, T* dest) { // Copy system info. dest->mPid = source.pid; dest->mMemory = source.memory; dest->mCpuTime = source.cpuTime; dest->mCpuCycleCount = source.cpuCycleCount; // Copy thread info. mozilla::dom::Sequence threads; for (const ThreadInfo& entry : source.threads) { mozilla::dom::ThreadInfoDictionary* thread = threads.AppendElement(fallible); if (NS_WARN_IF(!thread)) { return NS_ERROR_OUT_OF_MEMORY; } thread->mCpuTime = entry.cpuTime; thread->mCpuCycleCount = entry.cpuCycleCount; thread->mTid = entry.tid; thread->mName.Assign(entry.name); } dest->mThreads = std::move(threads); return NS_OK; } } // namespace mozilla #endif // ProcInfo_h