michael@0: // Copyright (c) 2009 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: // This file/namespace contains utility functions for enumerating, ending and michael@0: // computing statistics of processes. michael@0: michael@0: #ifndef BASE_PROCESS_UTIL_H_ michael@0: #define BASE_PROCESS_UTIL_H_ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #if defined(OS_WIN) michael@0: #include michael@0: #include michael@0: #elif defined(OS_LINUX) || defined(__GLIBC__) michael@0: #include michael@0: #include michael@0: #include michael@0: #elif defined(OS_MACOSX) michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "base/command_line.h" michael@0: #include "base/process.h" michael@0: michael@0: #if defined(OS_WIN) michael@0: typedef PROCESSENTRY32 ProcessEntry; michael@0: typedef IO_COUNTERS IoCounters; michael@0: #elif defined(OS_POSIX) michael@0: // TODO(port): we should not rely on a Win32 structure. michael@0: struct ProcessEntry { michael@0: int pid; michael@0: int ppid; michael@0: char szExeFile[NAME_MAX + 1]; michael@0: }; michael@0: michael@0: struct IoCounters { michael@0: unsigned long long ReadOperationCount; michael@0: unsigned long long WriteOperationCount; michael@0: unsigned long long OtherOperationCount; michael@0: unsigned long long ReadTransferCount; michael@0: unsigned long long WriteTransferCount; michael@0: unsigned long long OtherTransferCount; michael@0: }; michael@0: michael@0: #include "base/file_descriptor_shuffle.h" michael@0: #endif michael@0: michael@0: #if defined(OS_MACOSX) michael@0: struct kinfo_proc; michael@0: #endif michael@0: michael@0: namespace base { michael@0: michael@0: // These can be used in a 32-bit bitmask. michael@0: enum ProcessArchitecture { michael@0: PROCESS_ARCH_I386 = 0x1, michael@0: PROCESS_ARCH_X86_64 = 0x2, michael@0: PROCESS_ARCH_PPC = 0x4, michael@0: PROCESS_ARCH_ARM = 0x8 michael@0: }; michael@0: michael@0: inline ProcessArchitecture GetCurrentProcessArchitecture() michael@0: { michael@0: base::ProcessArchitecture currentArchitecture; michael@0: #if defined(ARCH_CPU_X86) michael@0: currentArchitecture = base::PROCESS_ARCH_I386; michael@0: #elif defined(ARCH_CPU_X86_64) michael@0: currentArchitecture = base::PROCESS_ARCH_X86_64; michael@0: #elif defined(ARCH_CPU_PPC) michael@0: currentArchitecture = base::PROCESS_ARCH_PPC; michael@0: #elif defined(ARCH_CPU_ARMEL) michael@0: currentArchitecture = base::PROCESS_ARCH_ARM; michael@0: #endif michael@0: return currentArchitecture; michael@0: } michael@0: michael@0: // A minimalistic but hopefully cross-platform set of exit codes. michael@0: // Do not change the enumeration values or you will break third-party michael@0: // installers. michael@0: enum { michael@0: PROCESS_END_NORMAL_TERMINATON = 0, michael@0: PROCESS_END_KILLED_BY_USER = 1, michael@0: PROCESS_END_PROCESS_WAS_HUNG = 2 michael@0: }; michael@0: michael@0: // Returns the id of the current process. michael@0: ProcessId GetCurrentProcId(); michael@0: michael@0: // Returns the ProcessHandle of the current process. michael@0: ProcessHandle GetCurrentProcessHandle(); michael@0: michael@0: // Converts a PID to a process handle. This handle must be closed by michael@0: // CloseProcessHandle when you are done with it. Returns true on success. michael@0: bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle); michael@0: michael@0: // Converts a PID to a process handle. On Windows the handle is opened michael@0: // with more access rights and must only be used by trusted code. michael@0: // You have to close returned handle using CloseProcessHandle. Returns true michael@0: // on success. michael@0: bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle); michael@0: michael@0: // Closes the process handle opened by OpenProcessHandle. michael@0: void CloseProcessHandle(ProcessHandle process); michael@0: michael@0: // Returns the unique ID for the specified process. This is functionally the michael@0: // same as Windows' GetProcessId(), but works on versions of Windows before michael@0: // Win XP SP1 as well. michael@0: ProcessId GetProcId(ProcessHandle process); michael@0: michael@0: #if defined(OS_POSIX) michael@0: // Sets all file descriptors to close on exec except for stdin, stdout michael@0: // and stderr. michael@0: // TODO(agl): remove this function michael@0: // WARNING: do not use. It's inherently race-prone in the face of michael@0: // multi-threading. michael@0: void SetAllFDsToCloseOnExec(); michael@0: // Close all file descriptors, expect those which are a destination in the michael@0: // given multimap. Only call this function in a child process where you know michael@0: // that there aren't any other threads. michael@0: void CloseSuperfluousFds(const base::InjectiveMultimap& saved_map); michael@0: #endif michael@0: michael@0: enum ChildPrivileges { michael@0: PRIVILEGES_DEFAULT, michael@0: PRIVILEGES_UNPRIVILEGED, michael@0: PRIVILEGES_INHERIT, michael@0: PRIVILEGES_LAST michael@0: }; michael@0: michael@0: #if defined(OS_WIN) michael@0: // Runs the given application name with the given command line. Normally, the michael@0: // first command line argument should be the path to the process, and don't michael@0: // forget to quote it. michael@0: // michael@0: // If wait is true, it will block and wait for the other process to finish, michael@0: // otherwise, it will just continue asynchronously. michael@0: // michael@0: // Example (including literal quotes) michael@0: // cmdline = "c:\windows\explorer.exe" -foo "c:\bar\" michael@0: // michael@0: // If process_handle is non-NULL, the process handle of the launched app will be michael@0: // stored there on a successful launch. michael@0: // NOTE: In this case, the caller is responsible for closing the handle so michael@0: // that it doesn't leak! michael@0: bool LaunchApp(const std::wstring& cmdline, michael@0: bool wait, bool start_hidden, ProcessHandle* process_handle); michael@0: #elif defined(OS_POSIX) michael@0: // Runs the application specified in argv[0] with the command line argv. michael@0: // Before launching all FDs open in the parent process will be marked as michael@0: // close-on-exec. |fds_to_remap| defines a mapping of src fd->dest fd to michael@0: // propagate FDs into the child process. michael@0: // michael@0: // As above, if wait is true, execute synchronously. The pid will be stored michael@0: // in process_handle if that pointer is non-null. michael@0: // michael@0: // Note that the first argument in argv must point to the filename, michael@0: // and must be fully specified. michael@0: typedef std::vector > file_handle_mapping_vector; michael@0: bool LaunchApp(const std::vector& argv, michael@0: const file_handle_mapping_vector& fds_to_remap, michael@0: bool wait, ProcessHandle* process_handle); michael@0: michael@0: typedef std::map environment_map; michael@0: bool LaunchApp(const std::vector& argv, michael@0: const file_handle_mapping_vector& fds_to_remap, michael@0: const environment_map& env_vars_to_set, michael@0: ChildPrivileges privs, michael@0: bool wait, ProcessHandle* process_handle, michael@0: ProcessArchitecture arch=GetCurrentProcessArchitecture()); michael@0: bool LaunchApp(const std::vector& argv, michael@0: const file_handle_mapping_vector& fds_to_remap, michael@0: const environment_map& env_vars_to_set, michael@0: bool wait, ProcessHandle* process_handle, michael@0: ProcessArchitecture arch=GetCurrentProcessArchitecture()); michael@0: #endif michael@0: michael@0: // Adjust the privileges of this process to match |privs|. Only michael@0: // returns if privileges were successfully adjusted. michael@0: void SetCurrentProcessPrivileges(ChildPrivileges privs); michael@0: michael@0: // Executes the application specified by cl. This function delegates to one michael@0: // of the above two platform-specific functions. michael@0: bool LaunchApp(const CommandLine& cl, michael@0: bool wait, bool start_hidden, ProcessHandle* process_handle); michael@0: michael@0: // Used to filter processes by process ID. michael@0: class ProcessFilter { michael@0: public: michael@0: // Returns true to indicate set-inclusion and false otherwise. This method michael@0: // should not have side-effects and should be idempotent. michael@0: virtual bool Includes(ProcessId pid, ProcessId parent_pid) const = 0; michael@0: virtual ~ProcessFilter() { } michael@0: }; michael@0: michael@0: // Attempts to kill the process identified by the given process michael@0: // entry structure, giving it the specified exit code. If |wait| is true, wait michael@0: // for the process to be actually terminated before returning. michael@0: // Returns true if this is successful, false otherwise. michael@0: bool KillProcess(ProcessHandle process, int exit_code, bool wait); michael@0: michael@0: // Get the termination status (exit code) of the process and return true if the michael@0: // status indicates the process crashed. |child_exited| is set to true iff the michael@0: // child process has terminated. (|child_exited| may be NULL.) michael@0: // michael@0: // On Windows, it is an error to call this if the process hasn't terminated michael@0: // yet. On POSIX, |child_exited| is set correctly since we detect terminate in michael@0: // a different manner on POSIX. michael@0: bool DidProcessCrash(bool* child_exited, ProcessHandle handle); michael@0: michael@0: // This class provides a way to iterate through the list of processes michael@0: // on the current machine that were started from the given executable michael@0: // name. To use, create an instance and then call NextProcessEntry() michael@0: // until it returns false. michael@0: class NamedProcessIterator { michael@0: public: michael@0: NamedProcessIterator(const std::wstring& executable_name, michael@0: const ProcessFilter* filter); michael@0: ~NamedProcessIterator(); michael@0: michael@0: // If there's another process that matches the given executable name, michael@0: // returns a const pointer to the corresponding PROCESSENTRY32. michael@0: // If there are no more matching processes, returns NULL. michael@0: // The returned pointer will remain valid until NextProcessEntry() michael@0: // is called again or this NamedProcessIterator goes out of scope. michael@0: const ProcessEntry* NextProcessEntry(); michael@0: michael@0: private: michael@0: #if !defined(OS_BSD) || defined(__GLIBC__) michael@0: // Determines whether there's another process (regardless of executable) michael@0: // left in the list of all processes. Returns true and sets entry_ to michael@0: // that process's info if there is one, false otherwise. michael@0: bool CheckForNextProcess(); michael@0: michael@0: bool IncludeEntry(); michael@0: michael@0: // Initializes a PROCESSENTRY32 data structure so that it's ready for michael@0: // use with Process32First/Process32Next. michael@0: void InitProcessEntry(ProcessEntry* entry); michael@0: michael@0: std::wstring executable_name_; michael@0: #endif michael@0: michael@0: #if defined(OS_WIN) michael@0: HANDLE snapshot_; michael@0: bool started_iteration_; michael@0: #elif defined(OS_LINUX) || defined(__GLIBC__) michael@0: DIR *procfs_dir_; michael@0: #elif defined(OS_BSD) michael@0: std::vector content; michael@0: size_t nextEntry; michael@0: #elif defined(OS_MACOSX) michael@0: std::vector kinfo_procs_; michael@0: size_t index_of_kinfo_proc_; michael@0: #endif michael@0: #if !defined(OS_BSD) || defined(__GLIBC__) michael@0: ProcessEntry entry_; michael@0: const ProcessFilter* filter_; michael@0: #endif michael@0: michael@0: DISALLOW_EVIL_CONSTRUCTORS(NamedProcessIterator); michael@0: }; michael@0: michael@0: // Provides performance metrics for a specified process (CPU usage, memory and michael@0: // IO counters). To use it, invoke CreateProcessMetrics() to get an instance michael@0: // for a specific process, then access the information with the different get michael@0: // methods. michael@0: class ProcessMetrics { michael@0: public: michael@0: // Creates a ProcessMetrics for the specified process. michael@0: // The caller owns the returned object. michael@0: static ProcessMetrics* CreateProcessMetrics(ProcessHandle process); michael@0: michael@0: ~ProcessMetrics(); michael@0: michael@0: // Returns the CPU usage in percent since the last time this method was michael@0: // called. The first time this method is called it returns 0 and will return michael@0: // the actual CPU info on subsequent calls. michael@0: // Note that on multi-processor machines, the CPU usage value is for all michael@0: // CPUs. So if you have 2 CPUs and your process is using all the cycles michael@0: // of 1 CPU and not the other CPU, this method returns 50. michael@0: int GetCPUUsage(); michael@0: michael@0: private: michael@0: explicit ProcessMetrics(ProcessHandle process); michael@0: michael@0: ProcessHandle process_; michael@0: michael@0: int processor_count_; michael@0: michael@0: // Used to store the previous times so we can compute the CPU usage. michael@0: int64_t last_time_; michael@0: int64_t last_system_time_; michael@0: michael@0: DISALLOW_EVIL_CONSTRUCTORS(ProcessMetrics); michael@0: }; michael@0: michael@0: } // namespace base michael@0: michael@0: #if defined(OS_WIN) michael@0: // Undo the windows.h damage michael@0: #undef GetMessage michael@0: #undef CreateEvent michael@0: #undef GetClassName michael@0: #undef GetBinaryType michael@0: #endif michael@0: michael@0: #endif // BASE_PROCESS_UTIL_H_