diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-13 13:24:50 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-10-14 10:57:25 +0000 |
commit | af3d4809763ef308f08ced947a73b624729ac7ea (patch) | |
tree | 4402b911e30383f6c6dace1e8cf3b8e85355db3a /chromium/base/process | |
parent | 0e8ff63a407fe323e215bb1a2c423c09a4747c8a (diff) |
BASELINE: Update Chromium to 47.0.2526.14
Also adding in sources needed for spellchecking.
Change-Id: Idd44170fa1616f26315188970a8d5ba7d472b18a
Reviewed-by: Michael BrĂ¼ning <michael.bruning@theqtcompany.com>
Diffstat (limited to 'chromium/base/process')
28 files changed, 456 insertions, 402 deletions
diff --git a/chromium/base/process/BUILD.gn b/chromium/base/process/BUILD.gn index 3978b2e58cf..eabbde538f1 100644 --- a/chromium/base/process/BUILD.gn +++ b/chromium/base/process/BUILD.gn @@ -22,6 +22,7 @@ source_set("process") { "memory_linux.cc", "memory_mac.mm", "memory_win.cc", + "port_provider_mac.h", "process.h", "process_handle_freebsd.cc", "process_handle_linux.cc", @@ -41,7 +42,6 @@ source_set("process") { "process_iterator_openbsd.cc", "process_iterator_win.cc", "process_linux.cc", - "process_mac.cc", "process_metrics.cc", "process_metrics.h", "process_metrics_freebsd.cc", @@ -96,7 +96,10 @@ source_set("process") { } if (is_ios) { - sources += [ "process_metrics.cc" ] + sources += [ + "memory_stubs.cc", + "process_metrics.cc", + ] } configs += [ "//base:base_implementation" ] diff --git a/chromium/base/process/internal_linux.cc b/chromium/base/process/internal_linux.cc index 4f3fcaccbfb..e6c2119c141 100644 --- a/chromium/base/process/internal_linux.cc +++ b/chromium/base/process/internal_linux.cc @@ -97,8 +97,9 @@ bool ParseProcStats(const std::string& stats_data, close_parens_idx - (open_parens_idx + 1))); // Split the rest. - std::vector<std::string> other_stats; - SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats); + std::vector<std::string> other_stats = SplitString( + stats_data.substr(close_parens_idx + 2), " ", + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); for (size_t i = 0; i < other_stats.size(); ++i) proc_stats->push_back(other_stats[i]); return true; diff --git a/chromium/base/process/kill.h b/chromium/base/process/kill.h index dbd32e17058..bb4103fb643 100644 --- a/chromium/base/process/kill.h +++ b/chromium/base/process/kill.h @@ -37,6 +37,7 @@ enum TerminationStatus { // a hint. TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill #endif + TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched TERMINATION_STATUS_MAX_ENUM }; diff --git a/chromium/base/process/kill_win.cc b/chromium/base/process/kill_win.cc index 0da3a26ae4f..7cbf9489051 100644 --- a/chromium/base/process/kill_win.cc +++ b/chromium/base/process/kill_win.cc @@ -57,7 +57,7 @@ class TimerExpiredTask : public win::ObjectWatcher::Delegate { }; TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) { - watcher_.StartWatching(process_.Handle(), this); + watcher_.StartWatchingOnce(process_.Handle(), this); } TimerExpiredTask::~TimerExpiredTask() { diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h index 0e42cd006ff..42b8a7670d9 100644 --- a/chromium/base/process/launch.h +++ b/chromium/base/process/launch.h @@ -164,16 +164,6 @@ struct BASE_EXPORT LaunchOptions { // process' controlling terminal. int ctrl_terminal_fd; #endif // defined(OS_CHROMEOS) - -#if defined(OS_MACOSX) - // If this name is non-empty, the new child, after fork() but before exec(), - // will look up this server name in the bootstrap namespace. The resulting - // service port will be replaced as the bootstrap port in the child. Because - // the process's IPC space is cleared on exec(), any rights to the old - // bootstrap port will not be transferred to the new process. - std::string replacement_bootstrap_name; -#endif - #endif // !defined(OS_WIN) }; @@ -236,7 +226,7 @@ BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags); // Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran // chrome. This is not thread-safe: only call from main thread. -BASE_EXPORT void RouteStdioToConsole(); +BASE_EXPORT void RouteStdioToConsole(bool create_console_if_not_found); #endif // defined(OS_WIN) // Executes the application specified by |cl| and wait for it to exit. Stores @@ -245,6 +235,10 @@ BASE_EXPORT void RouteStdioToConsole(); // indicating success). BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output); +// Like GetAppOutput, but also includes stderr. +BASE_EXPORT bool GetAppOutputAndError(const CommandLine& cl, + std::string* output); + #if defined(OS_WIN) // A Windows-specific version of GetAppOutput that takes a command line string // instead of a CommandLine object. Useful for situations where you need to @@ -286,11 +280,6 @@ BASE_EXPORT void RaiseProcessToHighPriority(); // in the child after forking will restore the standard exception handler. // See http://crbug.com/20371/ for more details. void RestoreDefaultExceptionHandler(); - -// Look up the bootstrap server named |replacement_bootstrap_name| via the -// current |bootstrap_port|. Then replace the task's bootstrap port with the -// received right. -void ReplaceBootstrapPort(const std::string& replacement_bootstrap_name); #endif // defined(OS_MACOSX) // Creates a LaunchOptions object suitable for launching processes in a test diff --git a/chromium/base/process/launch_mac.cc b/chromium/base/process/launch_mac.cc index ce02475541e..5895eae4351 100644 --- a/chromium/base/process/launch_mac.cc +++ b/chromium/base/process/launch_mac.cc @@ -28,21 +28,4 @@ void RestoreDefaultExceptionHandler() { EXCEPTION_DEFAULT, THREAD_STATE_NONE); } -void ReplaceBootstrapPort(const std::string& new_bootstrap_name) { - // This function is called between fork() and exec(), so it should take care - // to run properly in that situation. - - mach_port_t port = MACH_PORT_NULL; - kern_return_t kr = bootstrap_look_up(bootstrap_port, - new_bootstrap_name.c_str(), &port); - if (kr != KERN_SUCCESS) { - RAW_LOG(FATAL, "Failed to look up replacement bootstrap port."); - } - - kr = task_set_bootstrap_port(mach_task_self(), port); - if (kr != KERN_SUCCESS) { - RAW_LOG(FATAL, "Failed to replace bootstrap port."); - } -} - } // namespace base diff --git a/chromium/base/process/launch_posix.cc b/chromium/base/process/launch_posix.cc index 99d8e3aa64d..f076733d783 100644 --- a/chromium/base/process/launch_posix.cc +++ b/chromium/base/process/launch_posix.cc @@ -22,7 +22,6 @@ #include <limits> #include <set> -#include "base/allocator/type_profiler_control.h" #include "base/command_line.h" #include "base/compiler_specific.h" #include "base/debug/debugger.h" @@ -392,11 +391,6 @@ Process LaunchProcess(const std::vector<std::string>& argv, } } - // Stop type-profiler. - // The profiler should be stopped between fork and exec since it inserts - // locks at new/delete expressions. See http://crbug.com/36678. - base::type_profiler::Controller::Stop(); - if (options.maximize_rlimits) { // Some resource limits need to be maximal in this child. for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) { @@ -415,8 +409,6 @@ Process LaunchProcess(const std::vector<std::string>& argv, #if defined(OS_MACOSX) RestoreDefaultExceptionHandler(); - if (!options.replacement_bootstrap_name.empty()) - ReplaceBootstrapPort(options.replacement_bootstrap_name); #endif // defined(OS_MACOSX) ResetChildSignalHandlersToDefaults(); @@ -530,7 +522,8 @@ enum GetAppOutputInternalResult { // path for the application; in that case, |envp| must be null, and it will use // the current environment. If |do_search_path| is false, |argv[0]| should fully // specify the path of the application, and |envp| will be used as the -// environment. Redirects stderr to /dev/null. +// environment. If |include_stderr| is true, includes stderr otherwise redirects +// it to /dev/null. // If we successfully start the application and get all requested output, we // return GOT_MAX_OUTPUT, or if there is a problem starting or exiting // the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS. @@ -543,6 +536,7 @@ enum GetAppOutputInternalResult { static GetAppOutputInternalResult GetAppOutputInternal( const std::vector<std::string>& argv, char* const envp[], + bool include_stderr, std::string* output, size_t max_output, bool do_search_path, @@ -591,13 +585,10 @@ static GetAppOutputInternalResult GetAppOutputInternal( if (dev_null < 0) _exit(127); - // Stop type-profiler. - // The profiler should be stopped between fork and exec since it inserts - // locks at new/delete expressions. See http://crbug.com/36678. - base::type_profiler::Controller::Stop(); - fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); - fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); + fd_shuffle1.push_back(InjectionArc( + include_stderr ? pipe_fd[1] : dev_null, + STDERR_FILENO, true)); fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); // Adding another element here? Remeber to increase the argument to // reserve(), above. @@ -666,11 +657,20 @@ bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { // Run |execve()| with the current environment and store "unlimited" data. int exit_code; GetAppOutputInternalResult result = GetAppOutputInternal( - argv, NULL, output, std::numeric_limits<std::size_t>::max(), true, + argv, NULL, false, output, std::numeric_limits<std::size_t>::max(), true, &exit_code); return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; } +bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { + // Run |execve()| with the current environment and store "unlimited" data. + int exit_code; + GetAppOutputInternalResult result = GetAppOutputInternal( + cl.argv(), NULL, true, output, std::numeric_limits<std::size_t>::max(), + true, &exit_code); + return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS; +} + // TODO(viettrungluu): Conceivably, we should have a timeout as well, so we // don't hang if what we're calling hangs. bool GetAppOutputRestricted(const CommandLine& cl, @@ -679,7 +679,7 @@ bool GetAppOutputRestricted(const CommandLine& cl, char* const empty_environ = NULL; int exit_code; GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), &empty_environ, output, max_output, false, &exit_code); + cl.argv(), &empty_environ, false, output, max_output, false, &exit_code); return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS); } @@ -689,8 +689,8 @@ bool GetAppOutputWithExitCode(const CommandLine& cl, int* exit_code) { // Run |execve()| with the current environment and store "unlimited" data. GetAppOutputInternalResult result = GetAppOutputInternal( - cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, - exit_code); + cl.argv(), NULL, false, output, std::numeric_limits<std::size_t>::max(), + true, exit_code); return result == EXECUTE_SUCCESS; } diff --git a/chromium/base/process/launch_win.cc b/chromium/base/process/launch_win.cc index fa59f1ae907..54b06675100 100644 --- a/chromium/base/process/launch_win.cc +++ b/chromium/base/process/launch_win.cc @@ -46,9 +46,91 @@ namespace { // process goes away. const DWORD kProcessKilledExitCode = 1; +bool GetAppOutputInternal(const StringPiece16& cl, + bool include_stderr, + std::string* output) { + HANDLE out_read = NULL; + HANDLE out_write = NULL; + + SECURITY_ATTRIBUTES sa_attr; + // Set the bInheritHandle flag so pipe handles are inherited. + sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle = TRUE; + sa_attr.lpSecurityDescriptor = NULL; + + // Create the pipe for the child process's STDOUT. + if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { + NOTREACHED() << "Failed to create pipe"; + return false; + } + + // Ensure we don't leak the handles. + win::ScopedHandle scoped_out_read(out_read); + win::ScopedHandle scoped_out_write(out_write); + + // Ensure the read handles to the pipes are not inherited. + if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { + NOTREACHED() << "Failed to disabled pipe inheritance"; + return false; + } + + FilePath::StringType writable_command_line_string; + writable_command_line_string.assign(cl.data(), cl.size()); + + STARTUPINFO start_info = {}; + + start_info.cb = sizeof(STARTUPINFO); + start_info.hStdOutput = out_write; + // Keep the normal stdin. + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + if (include_stderr) { + start_info.hStdError = out_write; + } else { + start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + } + start_info.dwFlags |= STARTF_USESTDHANDLES; + + // Create the child process. + PROCESS_INFORMATION temp_process_info = {}; + if (!CreateProcess(NULL, + &writable_command_line_string[0], + NULL, NULL, + TRUE, // Handles are inherited. + 0, NULL, NULL, &start_info, &temp_process_info)) { + NOTREACHED() << "Failed to start process"; + return false; + } + base::win::ScopedProcessInformation proc_info(temp_process_info); + + // Close our writing end of pipe now. Otherwise later read would not be able + // to detect end of child's output. + scoped_out_write.Close(); + + // Read output from the child process's pipe for STDOUT + const int kBufferSize = 1024; + char buffer[kBufferSize]; + + for (;;) { + DWORD bytes_read = 0; + BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); + if (!success || bytes_read == 0) + break; + output->append(buffer, bytes_read); + } + + // Let's wait for the process to finish. + WaitForSingleObject(proc_info.process_handle(), INFINITE); + + int exit_code; + base::TerminationStatus status = GetTerminationStatus( + proc_info.process_handle(), &exit_code); + return status != base::TERMINATION_STATUS_PROCESS_CRASHED && + status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; +} + } // namespace -void RouteStdioToConsole() { +void RouteStdioToConsole(bool create_console_if_not_found) { // Don't change anything if stdout or stderr already point to a // valid stream. // @@ -64,8 +146,22 @@ void RouteStdioToConsole() { // stdout/stderr on startup (before the handle IDs can be reused). // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was // invalid. - if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) - return; + if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) { + // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013. + // http://crbug.com/358267. Confirm that the underlying HANDLE is valid + // before aborting. + + // This causes NaCl tests to hang on XP for reasons unclear, perhaps due + // to not being able to inherit handles. Since it's only for debugging, + // and redirecting still works, punt for now. + if (base::win::GetVersion() < base::win::VERSION_VISTA) + return; + + intptr_t stdout_handle = _get_osfhandle(_fileno(stdout)); + intptr_t stderr_handle = _get_osfhandle(_fileno(stderr)); + if (stdout_handle >= 0 || stderr_handle >= 0) + return; + } if (!AttachConsole(ATTACH_PARENT_PROCESS)) { unsigned int result = GetLastError(); @@ -76,10 +172,14 @@ void RouteStdioToConsole() { // parent process is invalid (eg: crashed). if (result == ERROR_GEN_FAILURE) return; - // Make a new console if attaching to parent fails with any other error. - // It should be ERROR_INVALID_HANDLE at this point, which means the browser - // was likely not started from a console. - AllocConsole(); + if (create_console_if_not_found) { + // Make a new console if attaching to parent fails with any other error. + // It should be ERROR_INVALID_HANDLE at this point, which means the + // browser was likely not started from a console. + AllocConsole(); + } else { + return; + } } // Arbitrary byte count to use when buffering output lines. More @@ -274,76 +374,12 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) { return GetAppOutput(cl.GetCommandLineString(), output); } -bool GetAppOutput(const StringPiece16& cl, std::string* output) { - HANDLE out_read = NULL; - HANDLE out_write = NULL; - - SECURITY_ATTRIBUTES sa_attr; - // Set the bInheritHandle flag so pipe handles are inherited. - sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle = TRUE; - sa_attr.lpSecurityDescriptor = NULL; - - // Create the pipe for the child process's STDOUT. - if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { - NOTREACHED() << "Failed to create pipe"; - return false; - } - - // Ensure we don't leak the handles. - win::ScopedHandle scoped_out_read(out_read); - win::ScopedHandle scoped_out_write(out_write); - - // Ensure the read handle to the pipe for STDOUT is not inherited. - if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { - NOTREACHED() << "Failed to disabled pipe inheritance"; - return false; - } - - FilePath::StringType writable_command_line_string; - writable_command_line_string.assign(cl.data(), cl.size()); - - STARTUPINFO start_info = {}; - - start_info.cb = sizeof(STARTUPINFO); - start_info.hStdOutput = out_write; - // Keep the normal stdin and stderr. - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); - start_info.dwFlags |= STARTF_USESTDHANDLES; - - // Create the child process. - PROCESS_INFORMATION temp_process_info = {}; - if (!CreateProcess(NULL, - &writable_command_line_string[0], - NULL, NULL, - TRUE, // Handles are inherited. - 0, NULL, NULL, &start_info, &temp_process_info)) { - NOTREACHED() << "Failed to start process"; - return false; - } - base::win::ScopedProcessInformation proc_info(temp_process_info); - - // Close our writing end of pipe now. Otherwise later read would not be able - // to detect end of child's output. - scoped_out_write.Close(); - - // Read output from the child process's pipe for STDOUT - const int kBufferSize = 1024; - char buffer[kBufferSize]; - - for (;;) { - DWORD bytes_read = 0; - BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL); - if (!success || bytes_read == 0) - break; - output->append(buffer, bytes_read); - } - - // Let's wait for the process to finish. - WaitForSingleObject(proc_info.process_handle(), INFINITE); +bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { + return GetAppOutputInternal(cl.GetCommandLineString(), true, output); +} - return true; +bool GetAppOutput(const StringPiece16& cl, std::string* output) { + return GetAppOutputInternal(cl, false, output); } void RaiseProcessToHighPriority() { diff --git a/chromium/base/process/memory_mac.mm b/chromium/base/process/memory_mac.mm index 4d719f8054e..17249a239b9 100644 --- a/chromium/base/process/memory_mac.mm +++ b/chromium/base/process/memory_mac.mm @@ -246,7 +246,7 @@ void oom_killer_new() { // === Core Foundation CFAllocators === bool CanGetContextForCFAllocator() { - return !base::mac::IsOSLaterThanYosemite_DontCallThis(); + return !base::mac::IsOSLaterThanElCapitan_DontCallThis(); } CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { @@ -258,7 +258,8 @@ CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) { } else if (base::mac::IsOSLion() || base::mac::IsOSMountainLion() || base::mac::IsOSMavericks() || - base::mac::IsOSYosemite()) { + base::mac::IsOSYosemite() || + base::mac::IsOSElCapitan()) { ChromeCFAllocatorLions* our_allocator = const_cast<ChromeCFAllocatorLions*>( reinterpret_cast<const ChromeCFAllocatorLions*>(allocator)); diff --git a/chromium/base/process/memory_unittest.cc b/chromium/base/process/memory_unittest.cc index 0276b495915..98f049a3bf9 100644 --- a/chromium/base/process/memory_unittest.cc +++ b/chromium/base/process/memory_unittest.cc @@ -30,6 +30,16 @@ #endif #if defined(OS_WIN) + +#if defined(_MSC_VER) +// ssize_t needed for OutOfMemoryTest. +#if defined(_WIN64) +typedef __int64 ssize_t; +#else +typedef long ssize_t; +#endif +#endif + // HeapQueryInformation function pointer. typedef BOOL (WINAPI* HeapQueryFn) \ (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T); @@ -130,8 +140,9 @@ TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) { // OutOfMemoryTest cases. OpenBSD does not support these tests either. // Don't test these on ASan/TSan/MSan configurations: only test the real // allocator. -// TODO(vandebo) make this work on Windows too. -#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && \ +// Windows only supports these tests with the allocator shim in place. +#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && \ + !(defined(OS_WIN) && !defined(ALLOCATOR_SHIM)) && \ !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) #if defined(USE_TCMALLOC) @@ -151,6 +162,9 @@ class OutOfMemoryTest : public testing::Test { // Make test size as large as possible minus a few pages so // that alignment or other rounding doesn't make it wrap. test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024), + // A test size that is > 2Gb and will cause the allocators to reject + // the allocation due to security restrictions. See crbug.com/169327. + insecure_test_size_(std::numeric_limits<int>::max()), signed_test_size_(std::numeric_limits<ssize_t>::max()) { } @@ -163,6 +177,7 @@ class OutOfMemoryTest : public testing::Test { protected: void* value_; size_t test_size_; + size_t insecure_test_size_; ssize_t signed_test_size_; }; @@ -213,6 +228,47 @@ TEST_F(OutOfMemoryDeathTest, Calloc) { }, kOomRegex); } +// OS X has no 2Gb allocation limit. +// See https://crbug.com/169327. +#if !defined(OS_MACOSX) +TEST_F(OutOfMemoryDeathTest, SecurityNew) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = operator new(insecure_test_size_); + }, kOomRegex); +} + +TEST_F(OutOfMemoryDeathTest, SecurityNewArray) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = new char[insecure_test_size_]; + }, kOomRegex); +} + +TEST_F(OutOfMemoryDeathTest, SecurityMalloc) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = malloc(insecure_test_size_); + }, kOomRegex); +} + +TEST_F(OutOfMemoryDeathTest, SecurityRealloc) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = realloc(NULL, insecure_test_size_); + }, kOomRegex); +} + +TEST_F(OutOfMemoryDeathTest, SecurityCalloc) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = calloc(1024, insecure_test_size_ / 1024L); + }, kOomRegex); +} +#endif // !defined(OS_MACOSX) + +#if defined(OS_LINUX) + TEST_F(OutOfMemoryDeathTest, Valloc) { ASSERT_DEATH({ SetUpInDeathAssert(); @@ -220,7 +276,12 @@ TEST_F(OutOfMemoryDeathTest, Valloc) { }, kOomRegex); } -#if defined(OS_LINUX) +TEST_F(OutOfMemoryDeathTest, SecurityValloc) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = valloc(insecure_test_size_); + }, kOomRegex); +} #if PVALLOC_AVAILABLE == 1 TEST_F(OutOfMemoryDeathTest, Pvalloc) { @@ -229,6 +290,13 @@ TEST_F(OutOfMemoryDeathTest, Pvalloc) { value_ = pvalloc(test_size_); }, kOomRegex); } + +TEST_F(OutOfMemoryDeathTest, SecurityPvalloc) { + ASSERT_DEATH({ + SetUpInDeathAssert(); + value_ = pvalloc(insecure_test_size_); + }, kOomRegex); +} #endif // PVALLOC_AVAILABLE == 1 TEST_F(OutOfMemoryDeathTest, Memalign) { @@ -415,5 +483,5 @@ TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) { EXPECT_TRUE(value_ == NULL); } #endif // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) -#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && - // !defined(ADDRESS_SANITIZER) +#endif // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !(defined(OS_WIN) && + // !defined(ALLOCATOR_SHIM)) && !defined(MEMORY_TOOL_REPLACES_ALLOCATOR) diff --git a/chromium/base/process/memory_win.cc b/chromium/base/process/memory_win.cc index fc57b48f1f7..b949b5d8854 100644 --- a/chromium/base/process/memory_win.cc +++ b/chromium/base/process/memory_win.cc @@ -10,6 +10,21 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" +// malloc_unchecked is required to implement UncheckedMalloc properly. +// It's provided by allocator_shim_win.cc but since that's not always present, +// we provide a default that falls back to regular malloc. +typedef void* (*MallocFn)(size_t); +extern "C" void* (*const malloc_unchecked)(size_t); +extern "C" void* (*const malloc_default)(size_t) = &malloc; + +#if defined(_M_IX86) +#pragma comment(linker, "/alternatename:_malloc_unchecked=_malloc_default") +#elif defined(_M_X64) || defined(_M_ARM) +#pragma comment(linker, "/alternatename:malloc_unchecked=malloc_default") +#else +#error Unsupported platform +#endif + namespace base { namespace { @@ -17,10 +32,12 @@ namespace { #pragma warning(push) #pragma warning(disable: 4702) -int OnNoMemory(size_t) { +int OnNoMemory(size_t size) { // Kill the process. This is important for security since most of code // does not check the result of memory allocation. - __debugbreak(); + LOG(FATAL) << "Out of memory, size = " << size; + + // Safety check, make sure process exits here. _exit(1); return 0; } @@ -88,14 +105,9 @@ HMODULE GetModuleFromAddress(void* address) { return instance; } -// TODO(b.kelemen): implement it with the required semantics. On Linux this is -// implemented with a weak symbol that is overridden by tcmalloc. This is -// neccessary because base cannot have a direct dependency on tcmalloc. Since -// weak symbols are not supported on Windows this will involve some build time -// magic, much like what is done for libcrt in order to override the allocation -// functions. +// Implemented using a weak symbol. bool UncheckedMalloc(size_t size, void** result) { - *result = malloc(size); + *result = malloc_unchecked(size); return *result != NULL; } diff --git a/chromium/base/process/port_provider_mac.h b/chromium/base/process/port_provider_mac.h new file mode 100644 index 00000000000..bdee4a8a293 --- /dev/null +++ b/chromium/base/process/port_provider_mac.h @@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_PROCESS_PORT_PROVIDER_MAC_H_ +#define BASE_PROCESS_PORT_PROVIDER_MAC_H_ + +#include <mach/mach.h> + +#include "base/base_export.h" +#include "base/process/process_handle.h" + +namespace base { + +// Abstract base class that provides a mapping from ProcessHandle (pid_t) to the +// Mach task port. This replicates task_for_pid(), which requires root +// privileges. +class BASE_EXPORT PortProvider { + public: + virtual ~PortProvider() {} + + // Returns the mach task port for |process| if possible, or else + // |MACH_PORT_NULL|. + virtual mach_port_t TaskForPid(ProcessHandle process) const = 0; +}; + +} // namespace base + +#endif // BASE_PROCESS_PORT_PROVIDER_MAC_H_ diff --git a/chromium/base/process/process.h b/chromium/base/process/process.h index 1559554c011..2a83cb088ac 100644 --- a/chromium/base/process/process.h +++ b/chromium/base/process/process.h @@ -111,24 +111,6 @@ class BASE_EXPORT Process { // is not required. bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code); -#if defined(OS_MACOSX) - // The Mac needs a Mach port in order to manipulate a process's priority, - // and there's no good way to get that from base given the pid. These Mac - // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take - // the Mach port for this reason. See crbug.com/460102 - // - // A process is backgrounded when its priority is lower than normal. - // Return true if the process with mach port |task_port| is backgrounded, - // false otherwise. - bool IsProcessBackgrounded(mach_port_t task_port) const; - - // Set the process with the specified mach port as backgrounded. If value is - // true, the priority of the process will be lowered. If value is false, the - // priority of the process will be made "normal" - equivalent to default - // process priority. Returns true if the priority was changed, false - // otherwise. - bool SetProcessBackgrounded(mach_port_t task_port, bool value); -#else // A process is backgrounded when it's priority is lower than normal. // Return true if this process is backgrounded, false otherwise. bool IsProcessBackgrounded() const; @@ -138,7 +120,7 @@ class BASE_EXPORT Process { // will be made "normal" - equivalent to default process priority. // Returns true if the priority was changed, false otherwise. bool SetProcessBackgrounded(bool value); -#endif // defined(OS_MACOSX) + // Returns an integer representing the priority of a process. The meaning // of this value is OS dependent. int GetPriority() const; diff --git a/chromium/base/process/process_info_linux.cc b/chromium/base/process/process_info_linux.cc index 9ec23135bfc..88ae5a137d6 100644 --- a/chromium/base/process/process_info_linux.cc +++ b/chromium/base/process/process_info_linux.cc @@ -12,7 +12,7 @@ namespace base { -//static +// static const Time CurrentProcessInfo::CreationTime() { ProcessHandle pid = GetCurrentProcessHandle(); int64 start_ticks = diff --git a/chromium/base/process/process_info_mac.cc b/chromium/base/process/process_info_mac.cc index b7cfdceda05..7680d373df3 100644 --- a/chromium/base/process/process_info_mac.cc +++ b/chromium/base/process/process_info_mac.cc @@ -14,7 +14,7 @@ namespace base { -//static +// static const Time CurrentProcessInfo::CreationTime() { int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; size_t len = 0; diff --git a/chromium/base/process/process_iterator_mac.cc b/chromium/base/process/process_iterator_mac.cc index 9b33a0a8e40..d9136f48b03 100644 --- a/chromium/base/process/process_iterator_mac.cc +++ b/chromium/base/process/process_iterator_mac.cc @@ -22,7 +22,8 @@ ProcessIterator::ProcessIterator(const ProcessFilter* filter) // but trying to find where we were in a constantly changing list is basically // impossible. - int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() }; + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, + static_cast<int>(geteuid()) }; // Since more processes could start between when we get the size and when // we get the list, we do a loop to keep trying until we get it. diff --git a/chromium/base/process/process_linux.cc b/chromium/base/process/process_linux.cc index 6e10dd2301f..958ffd6dafb 100644 --- a/chromium/base/process/process_linux.cc +++ b/chromium/base/process/process_linux.cc @@ -102,8 +102,8 @@ bool Process::IsProcessBackgrounded() const { if (base::ReadFileToString( base::FilePath(StringPrintf(kProcPath, process_)), &proc)) { - std::vector<std::string> proc_parts; - base::SplitString(proc, ':', &proc_parts); + std::vector<std::string> proc_parts = base::SplitString( + proc, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); DCHECK_EQ(proc_parts.size(), 3u); bool ret = proc_parts[2] == std::string(kBackground); return ret; diff --git a/chromium/base/process/process_mac.cc b/chromium/base/process/process_mac.cc deleted file mode 100644 index 1913cc378e8..00000000000 --- a/chromium/base/process/process_mac.cc +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/process/process.h" - -#include "base/mac/mac_util.h" -#include "base/mac/mach_logging.h" - -#include <mach/mach.h> - -// The following was added to <mach/task_policy.h> after 10.8. -// TODO(shrike): Remove the TASK_OVERRIDE_QOS_POLICY ifndef once builders -// reach 10.9 or higher. -#ifndef TASK_OVERRIDE_QOS_POLICY - -#define TASK_OVERRIDE_QOS_POLICY 9 - -typedef struct task_category_policy task_category_policy_data_t; -typedef struct task_category_policy* task_category_policy_t; - -enum task_latency_qos { - LATENCY_QOS_TIER_UNSPECIFIED = 0x0, - LATENCY_QOS_TIER_0 = ((0xFF << 16) | 1), - LATENCY_QOS_TIER_1 = ((0xFF << 16) | 2), - LATENCY_QOS_TIER_2 = ((0xFF << 16) | 3), - LATENCY_QOS_TIER_3 = ((0xFF << 16) | 4), - LATENCY_QOS_TIER_4 = ((0xFF << 16) | 5), - LATENCY_QOS_TIER_5 = ((0xFF << 16) | 6) -}; -typedef integer_t task_latency_qos_t; -enum task_throughput_qos { - THROUGHPUT_QOS_TIER_UNSPECIFIED = 0x0, - THROUGHPUT_QOS_TIER_0 = ((0xFE << 16) | 1), - THROUGHPUT_QOS_TIER_1 = ((0xFE << 16) | 2), - THROUGHPUT_QOS_TIER_2 = ((0xFE << 16) | 3), - THROUGHPUT_QOS_TIER_3 = ((0xFE << 16) | 4), - THROUGHPUT_QOS_TIER_4 = ((0xFE << 16) | 5), - THROUGHPUT_QOS_TIER_5 = ((0xFE << 16) | 6), -}; - -#define LATENCY_QOS_LAUNCH_DEFAULT_TIER LATENCY_QOS_TIER_3 -#define THROUGHPUT_QOS_LAUNCH_DEFAULT_TIER THROUGHPUT_QOS_TIER_3 - -typedef integer_t task_throughput_qos_t; - -struct task_qos_policy { - task_latency_qos_t task_latency_qos_tier; - task_throughput_qos_t task_throughput_qos_tier; -}; - -typedef struct task_qos_policy* task_qos_policy_t; -#define TASK_QOS_POLICY_COUNT \ - ((mach_msg_type_number_t)(sizeof(struct task_qos_policy) / sizeof(integer_t))) - -#endif // TASK_OVERRIDE_QOS_POLICY - -namespace base { - -bool Process::CanBackgroundProcesses() { - return true; -} - -bool Process::IsProcessBackgrounded(mach_port_t task_port) const { - // See SetProcessBackgrounded(). - DCHECK(IsValid()); - DCHECK_NE(task_port, TASK_NULL); - - task_category_policy_data_t category_policy; - mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT; - boolean_t get_default = FALSE; - - kern_return_t result = - task_policy_get(task_port, TASK_CATEGORY_POLICY, - reinterpret_cast<task_policy_t>(&category_policy), - &task_info_count, &get_default); - MACH_LOG_IF(ERROR, result != KERN_SUCCESS, result) << - "task_policy_get TASK_CATEGORY_POLICY"; - - if (result == KERN_SUCCESS && get_default == FALSE) { - return category_policy.role == TASK_BACKGROUND_APPLICATION; - } - return false; -} - -bool Process::SetProcessBackgrounded(mach_port_t task_port, bool background) { - DCHECK(IsValid()); - DCHECK_NE(task_port, TASK_NULL); - - if (!CanBackgroundProcesses()) { - return false; - } else if (IsProcessBackgrounded(task_port) == background) { - return true; - } - - task_category_policy category_policy; - category_policy.role = - background ? TASK_BACKGROUND_APPLICATION : TASK_FOREGROUND_APPLICATION; - kern_return_t result = - task_policy_set(task_port, TASK_CATEGORY_POLICY, - reinterpret_cast<task_policy_t>(&category_policy), - TASK_CATEGORY_POLICY_COUNT); - - if (result != KERN_SUCCESS) { - MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY"; - return false; - } else if (!mac::IsOSMavericksOrLater()) { - return true; - } - - // Latency QoS regulates timer throttling/accuracy. Select default tier - // on foreground because precise timer firing isn't needed. - struct task_qos_policy qos_policy = { - background ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED, - background ? THROUGHPUT_QOS_TIER_5 : THROUGHPUT_QOS_TIER_UNSPECIFIED - }; - result = task_policy_set(task_port, TASK_OVERRIDE_QOS_POLICY, - reinterpret_cast<task_policy_t>(&qos_policy), - TASK_QOS_POLICY_COUNT); - if (result != KERN_SUCCESS) { - MACH_LOG(ERROR, result) << "task_policy_set TASK_OVERRIDE_QOS_POLICY"; - return false; - } - - return true; -} - -} // namespace base diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h index 8b4ec86693a..327483a42e7 100644 --- a/chromium/base/process/process_metrics.h +++ b/chromium/base/process/process_metrics.h @@ -19,6 +19,7 @@ #if defined(OS_MACOSX) #include <mach/mach.h> +#include "base/process/port_provider_mac.h" #endif namespace base { @@ -101,16 +102,6 @@ class BASE_EXPORT ProcessMetrics { #if !defined(OS_MACOSX) || defined(OS_IOS) static ProcessMetrics* CreateProcessMetrics(ProcessHandle process); #else - class PortProvider { - public: - virtual ~PortProvider() {} - - // Should return the mach task for |process| if possible, or else - // |MACH_PORT_NULL|. Only processes that this returns tasks for will have - // metrics on OS X (except for the current process, which always gets - // metrics). - virtual mach_port_t TaskForPid(ProcessHandle process) const = 0; - }; // The port provider needs to outlive the ProcessMetrics object returned by // this function. If NULL is passed as provider, the returned object @@ -242,23 +233,16 @@ BASE_EXPORT size_t GetMaxFds(); BASE_EXPORT void SetFdLimit(unsigned int max_descriptors); #endif // defined(OS_POSIX) -#if defined(OS_LINUX) || defined(OS_ANDROID) -// Parse the data found in /proc/<pid>/stat and return the sum of the -// CPU-related ticks. Returns -1 on parse error. -// Exposed for testing. -BASE_EXPORT int ParseProcStatCPU(const std::string& input); - -// Get the number of threads of |process| as available in /proc/<pid>/stat. -// This should be used with care as no synchronization with running threads is -// done. This is mostly useful to guarantee being single-threaded. -// Returns 0 on failure. -BASE_EXPORT int GetNumberOfThreads(ProcessHandle process); - -// /proc/self/exe refers to the current executable. -BASE_EXPORT extern const char kProcSelfExe[]; - -// Data from /proc/meminfo about system-wide memory consumption. -// Values are in KB. +#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ + defined(OS_ANDROID) +// Data about system-wide memory consumption. Values are in KB. Available on +// Windows, Mac, Linux, Android and Chrome OS. +// +// Total/free memory are available on all platforms that implement +// GetSystemMemoryInfo(). Total/free swap memory are available on all platforms +// except on Mac. Buffers/cached/active_anon/inactive_anon/active_file/ +// inactive_file/dirty/pswpin/pswpout/pgmajfault are available on +// Linux/Android/Chrome OS. Shmem/slab/gem_objects/gem_size are Chrome OS only. struct BASE_EXPORT SystemMemoryInfoKB { SystemMemoryInfoKB(); @@ -267,30 +251,62 @@ struct BASE_EXPORT SystemMemoryInfoKB { int total; int free; + +#if !defined(OS_MACOSX) + int swap_total; + int swap_free; +#endif + +#if defined(OS_ANDROID) || defined(OS_LINUX) int buffers; int cached; int active_anon; int inactive_anon; int active_file; int inactive_file; - int swap_total; - int swap_free; int dirty; // vmstats data. int pswpin; int pswpout; int pgmajfault; +#endif // defined(OS_ANDROID) || defined(OS_LINUX) -#ifdef OS_CHROMEOS +#if defined(OS_CHROMEOS) int shmem; int slab; // Gem data will be -1 if not supported. int gem_objects; long long gem_size; -#endif +#endif // defined(OS_CHROMEOS) }; +// On Linux/Android/Chrome OS, system-wide memory consumption data is parsed +// from /proc/meminfo and /proc/vmstat. On Windows/Mac, it is obtained using +// system API calls. +// +// Fills in the provided |meminfo| structure. Returns true on success. +// Exposed for memory debugging widget. +BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo); + +#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || + // defined(OS_ANDROID) + +#if defined(OS_LINUX) || defined(OS_ANDROID) +// Parse the data found in /proc/<pid>/stat and return the sum of the +// CPU-related ticks. Returns -1 on parse error. +// Exposed for testing. +BASE_EXPORT int ParseProcStatCPU(const std::string& input); + +// Get the number of threads of |process| as available in /proc/<pid>/stat. +// This should be used with care as no synchronization with running threads is +// done. This is mostly useful to guarantee being single-threaded. +// Returns 0 on failure. +BASE_EXPORT int GetNumberOfThreads(ProcessHandle process); + +// /proc/self/exe refers to the current executable. +BASE_EXPORT extern const char kProcSelfExe[]; + // Parses a string containing the contents of /proc/meminfo // returns true on success or false for a parsing error BASE_EXPORT bool ParseProcMeminfo(const std::string& input, @@ -301,12 +317,6 @@ BASE_EXPORT bool ParseProcMeminfo(const std::string& input, BASE_EXPORT bool ParseProcVmstat(const std::string& input, SystemMemoryInfoKB* meminfo); -// Retrieves data from /proc/meminfo and /proc/vmstat -// about system-wide memory consumption. -// Fills in the provided |meminfo| structure. Returns true on success. -// Exposed for memory debugging widget. -BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo); - // Data from /proc/diskstats about system-wide disk I/O. struct BASE_EXPORT SystemDiskInfo { SystemDiskInfo(); diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc index 07f2c8de1d4..135ef43c06c 100644 --- a/chromium/base/process/process_metrics_ios.cc +++ b/chromium/base/process/process_metrics_ios.cc @@ -23,6 +23,11 @@ bool GetTaskInfo(task_basic_info_64* task_info_data) { } // namespace +SystemMemoryInfoKB::SystemMemoryInfoKB() { + total = 0; + free = 0; +} + ProcessMetrics::ProcessMetrics(ProcessHandle process) {} ProcessMetrics::~ProcessMetrics() {} @@ -82,4 +87,11 @@ size_t GetSystemCommitCharge() { return 0; } +// Bytes committed by the system. +bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { + // Unimplemented. Must enable unittest for IOS when this gets implemented. + NOTIMPLEMENTED(); + return false; +} + } // namespace base diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc index 47a79e51e5e..adca7c5ee23 100644 --- a/chromium/base/process/process_metrics_linux.cc +++ b/chromium/base/process/process_metrics_linux.cc @@ -67,8 +67,8 @@ size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) { const std::string& key = pairs[i].first; const std::string& value_str = pairs[i].second; if (key == field) { - std::vector<std::string> split_value_str; - SplitString(value_str, ' ', &split_value_str); + std::vector<StringPiece> split_value_str = SplitStringPiece( + value_str, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); if (split_value_str.size() != 2 || split_value_str[1] != "kB") { NOTREACHED(); return 0; @@ -316,8 +316,9 @@ bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) return false; } - std::vector<std::string> totmaps_fields; - SplitStringAlongWhitespace(totmaps_data, &totmaps_fields); + std::vector<std::string> totmaps_fields = SplitString( + totmaps_data, base::kWhitespaceASCII, base::KEEP_WHITESPACE, + base::SPLIT_WANT_NONEMPTY); DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]); DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]); @@ -368,8 +369,8 @@ bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) return false; } - std::vector<std::string> statm_vec; - SplitString(statm, ' ', &statm_vec); + std::vector<StringPiece> statm_vec = SplitStringPiece( + statm, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); if (statm_vec.size() != 7) return false; // Not the format we expect. diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc index f84b435a109..a2ecd8e7185 100644 --- a/chromium/base/process/process_metrics_mac.cc +++ b/chromium/base/process/process_metrics_mac.cc @@ -77,6 +77,11 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { } // namespace +SystemMemoryInfoKB::SystemMemoryInfoKB() { + total = 0; + free = 0; +} + // Getting a mach task from a pid for another process requires permissions in // general, so there doesn't really seem to be a way to do these (and spinning // up ps to fetch each stats seems dangerous to put in a base api for anyone to @@ -86,7 +91,7 @@ bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) { // static ProcessMetrics* ProcessMetrics::CreateProcessMetrics( ProcessHandle process, - ProcessMetrics::PortProvider* port_provider) { + PortProvider* port_provider) { return new ProcessMetrics(process, port_provider); } @@ -325,7 +330,7 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const { } ProcessMetrics::ProcessMetrics(ProcessHandle process, - ProcessMetrics::PortProvider* port_provider) + PortProvider* port_provider) : process_(process), last_system_time_(0), last_absolute_idle_wakeups_(0), @@ -358,4 +363,32 @@ size_t GetSystemCommitCharge() { return (data.active_count * PAGE_SIZE) / 1024; } +// On Mac, We only get total memory and free memory from the system. +bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { + struct host_basic_info hostinfo; + mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; + base::mac::ScopedMachSendRight host(mach_host_self()); + int result = host_info(host, HOST_BASIC_INFO, + reinterpret_cast<host_info_t>(&hostinfo), &count); + if (result != KERN_SUCCESS) + return false; + + DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); + meminfo->total = static_cast<int>(hostinfo.max_mem / 1024); + + vm_statistics_data_t vm_info; + count = HOST_VM_INFO_COUNT; + + if (host_statistics(host.get(), HOST_VM_INFO, + reinterpret_cast<host_info_t>(&vm_info), + &count) != KERN_SUCCESS) { + return false; + } + + meminfo->free = static_cast<int>( + (vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE / 1024); + + return true; +} + } // namespace base diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc index 76767b09a95..31479cefff6 100644 --- a/chromium/base/process/process_metrics_unittest.cc +++ b/chromium/base/process/process_metrics_unittest.cc @@ -270,7 +270,8 @@ TEST_F(SystemMetricsTest, ParseVmstat) { } #endif // defined(OS_LINUX) || defined(OS_ANDROID) -#if defined(OS_LINUX) || defined(OS_ANDROID) +#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \ + defined(OS_LINUX) || defined(OS_ANDROID) TEST(SystemMetrics2Test, GetSystemMemoryInfo) { base::SystemMemoryInfoKB info; EXPECT_TRUE(base::GetSystemMemoryInfo(&info)); @@ -278,21 +279,25 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) { // Ensure each field received a value. EXPECT_GT(info.total, 0); EXPECT_GT(info.free, 0); +#if defined(OS_LINUX) || defined(OS_ANDROID) EXPECT_GT(info.buffers, 0); EXPECT_GT(info.cached, 0); EXPECT_GT(info.active_anon, 0); EXPECT_GT(info.inactive_anon, 0); EXPECT_GT(info.active_file, 0); EXPECT_GT(info.inactive_file, 0); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) // All the values should be less than the total amount of memory. EXPECT_LT(info.free, info.total); +#if defined(OS_LINUX) || defined(OS_ANDROID) EXPECT_LT(info.buffers, info.total); EXPECT_LT(info.cached, info.total); EXPECT_LT(info.active_anon, info.total); EXPECT_LT(info.inactive_anon, info.total); EXPECT_LT(info.active_file, info.total); EXPECT_LT(info.inactive_file, info.total); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_CHROMEOS) // Chrome OS exposes shmem. @@ -302,7 +307,8 @@ TEST(SystemMetrics2Test, GetSystemMemoryInfo) { // and gem_size cannot be tested here. #endif } -#endif // defined(OS_LINUX) || defined(OS_ANDROID) +#endif // defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || + // defined(OS_LINUX) || defined(OS_ANDROID) #if defined(OS_LINUX) || defined(OS_ANDROID) TEST(ProcessMetricsTest, ParseProcStatCPU) { diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc index 170f6dcaab8..c3b3e50ff61 100644 --- a/chromium/base/process/process_metrics_win.cc +++ b/chromium/base/process/process_metrics_win.cc @@ -6,15 +6,32 @@ #include <windows.h> #include <psapi.h> +#include <winternl.h> #include "base/logging.h" #include "base/sys_info.h" namespace base { +namespace { // System pagesize. This value remains constant on x86/64 architectures. const int PAGESIZE_KB = 4; +typedef NTSTATUS(WINAPI* NTQUERYSYSTEMINFORMATION)( + SYSTEM_INFORMATION_CLASS SystemInformationClass, + PVOID SystemInformation, + ULONG SystemInformationLength, + PULONG ReturnLength); + +} // namespace + +SystemMemoryInfoKB::SystemMemoryInfoKB() { + total = 0; + free = 0; + swap_total = 0; + swap_free = 0; +} + ProcessMetrics::~ProcessMetrics() { } // static @@ -285,4 +302,24 @@ size_t GetPageSize() { return PAGESIZE_KB * 1024; } +// This function uses the following mapping between MEMORYSTATUSEX and +// SystemMemoryInfoKB: +// ullTotalPhys ==> total +// ullAvailPhys ==> free +// ullTotalPageFile ==> swap_total +// ullAvailPageFile ==> swap_free +bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) { + MEMORYSTATUSEX mem_status; + mem_status.dwLength = sizeof(mem_status); + if (!::GlobalMemoryStatusEx(&mem_status)) + return false; + + meminfo->total = mem_status.ullTotalPhys / 1024; + meminfo->free = mem_status.ullAvailPhys / 1024; + meminfo->swap_total = mem_status.ullTotalPageFile / 1024; + meminfo->swap_free = mem_status.ullAvailPageFile / 1024; + + return true; +} + } // namespace base diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc index b6f22c1edcf..72e49faefca 100644 --- a/chromium/base/process/process_posix.cc +++ b/chromium/base/process/process_posix.cc @@ -255,12 +255,12 @@ Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) { return Process(handle); } -#if !defined(OS_LINUX) && !defined(OS_MACOSX) +#if !defined(OS_LINUX) // static bool Process::CanBackgroundProcesses() { return false; } -#endif // !defined(OS_LINUX) && !defined(OS_MACOSX) +#endif // !defined(OS_LINUX) bool Process::IsValid() const { return process_ != kNullProcessHandle; @@ -356,7 +356,7 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout); } -#if !defined(OS_LINUX) && !defined(OS_MACOSX) +#if !defined(OS_LINUX) bool Process::IsProcessBackgrounded() const { // See SetProcessBackgrounded(). DCHECK(IsValid()); @@ -364,13 +364,13 @@ bool Process::IsProcessBackgrounded() const { } bool Process::SetProcessBackgrounded(bool value) { - // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if - // we were to lower the process priority we wouldn't be able to raise it back - // to its initial priority. + // Not implemented for POSIX systems other than Linux. With POSIX, if we were + // to lower the process priority we wouldn't be able to raise it back to its + // initial priority. NOTIMPLEMENTED(); return false; } -#endif // !defined(OS_LINUX) && !defined(OS_MACOSX) +#endif // !defined(OS_LINUX) int Process::GetPriority() const { DCHECK(IsValid()); diff --git a/chromium/base/process/process_unittest.cc b/chromium/base/process/process_unittest.cc index e094c032f3b..9fdc2f1e028 100644 --- a/chromium/base/process/process_unittest.cc +++ b/chromium/base/process/process_unittest.cc @@ -11,10 +11,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" -#if defined(OS_MACOSX) -#include <mach/mach.h> -#endif // OS_MACOSX - namespace { #if defined(OS_WIN) @@ -174,26 +170,16 @@ TEST_F(ProcessTest, WaitForExitWithTimeout) { TEST_F(ProcessTest, SetProcessBackgrounded) { Process process(SpawnChild("SimpleChildProcess")); int old_priority = process.GetPriority(); -#if defined(OS_MACOSX) - // On the Mac, backgrounding a process requires a port to that process. - // In the browser it's available through the MachBroker class, which is not - // part of base. Additionally, there is an indefinite amount of time between - // spawning a process and receiving its port. Because this test just checks - // the ability to background/foreground a process, we can use the current - // process's port instead. - mach_port_t process_port = mach_task_self(); - EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true)); - EXPECT_TRUE(process.IsProcessBackgrounded(process_port)); - EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false)); - EXPECT_FALSE(process.IsProcessBackgrounded(process_port)); -#elif defined(OS_WIN) +#if defined(OS_WIN) EXPECT_TRUE(process.SetProcessBackgrounded(true)); EXPECT_TRUE(process.IsProcessBackgrounded()); EXPECT_TRUE(process.SetProcessBackgrounded(false)); EXPECT_FALSE(process.IsProcessBackgrounded()); #else - process.SetProcessBackgrounded(true); - process.SetProcessBackgrounded(false); + if (process.CanBackgroundProcesses()) { + process.SetProcessBackgrounded(true); + process.SetProcessBackgrounded(false); + } #endif int new_priority = process.GetPriority(); EXPECT_EQ(old_priority, new_priority); @@ -204,13 +190,7 @@ TEST_F(ProcessTest, SetProcessBackgrounded) { TEST_F(ProcessTest, SetProcessBackgroundedSelf) { Process process = Process::Current(); int old_priority = process.GetPriority(); -#if defined(OS_MACOSX) - mach_port_t process_port = mach_task_self(); - EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true)); - EXPECT_TRUE(process.IsProcessBackgrounded(process_port)); - EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false)); - EXPECT_FALSE(process.IsProcessBackgrounded(process_port)); -#elif defined(OS_WIN) +#if defined(OS_WIN) EXPECT_TRUE(process.SetProcessBackgrounded(true)); EXPECT_TRUE(process.IsProcessBackgrounded()); EXPECT_TRUE(process.SetProcessBackgrounded(false)); diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc index 6c1a3f1d761..08144f2a18e 100644 --- a/chromium/base/process/process_util_unittest.cc +++ b/chromium/base/process/process_util_unittest.cc @@ -59,6 +59,9 @@ #include <malloc/malloc.h> #include "base/mac/mac_util.h" #endif +#if defined(OS_ANDROID) +#include "third_party/lss/linux_syscall_support.h" +#endif using base::FilePath; @@ -75,7 +78,7 @@ const char kShellPath[] = "/system/bin/sh"; const char kPosixShell[] = "sh"; #else const char kShellPath[] = "/bin/sh"; -const char kPosixShell[] = "bash"; +const char kPosixShell[] = "sh"; #endif #endif // defined(OS_POSIX) @@ -226,7 +229,19 @@ const char kSignalFileCrash[] = "CrashingChildProcess.die"; MULTIPROCESS_TEST_MAIN(CrashingChildProcess) { WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str()); -#if defined(OS_POSIX) +#if defined(OS_ANDROID) + // Android L+ expose signal and sigaction symbols that override the system + // ones. There is a bug in these functions where a request to set the handler + // to SIG_DFL is ignored. In that case, an infinite loop is entered as the + // signal is repeatedly sent to the crash dump signal handler. + // To work around this, directly call the system's sigaction. + struct kernel_sigaction sa; + memset(&sa, 0, sizeof(sa)); + sys_sigemptyset(&sa.sa_mask); + sa.sa_handler_ = SIG_DFL; + sa.sa_flags = SA_RESTART; + sys_rt_sigaction(SIGSEGV, &sa, NULL, sizeof(kernel_sigset_t)); +#elif defined(OS_POSIX) // Have to disable to signal handler for segv so we can get a crash // instead of an abnormal termination through the crash dump handler. ::signal(SIGSEGV, SIG_DFL); diff --git a/chromium/base/process/process_win.cc b/chromium/base/process/process_win.cc index 30cd9dc7372..818864fa528 100644 --- a/chromium/base/process/process_win.cc +++ b/chromium/base/process/process_win.cc @@ -6,10 +6,8 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" -#include "base/metrics/field_trial.h" #include "base/numerics/safe_conversions.h" #include "base/process/kill.h" -#include "base/strings/string_util.h" #include "base/win/windows_version.h" namespace { @@ -179,23 +177,7 @@ bool Process::SetProcessBackgrounded(bool value) { priority = value ? PROCESS_MODE_BACKGROUND_BEGIN : PROCESS_MODE_BACKGROUND_END; } else { - // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a - // background priority for background renderers (this code path is - // technically for more than just the renderers but they're the only use - // case in practice and experimenting here direclty is thus easier -- plus - // it doesn't really hurt as above we already state our intent of using - // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially - // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the - // asbence of field trials to get coverage on the perf waterfall. - DWORD background_priority = IDLE_PRIORITY_CLASS; - base::FieldTrial* trial = - base::FieldTrialList::Find("BackgroundRendererProcesses"); - if (trial && StartsWith(trial->group_name(), "AllowBelowNormalFromBrowser", - CompareCase::SENSITIVE)) { - background_priority = BELOW_NORMAL_PRIORITY_CLASS; - } - - priority = value ? background_priority : NORMAL_PRIORITY_CLASS; + priority = value ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; } return (::SetPriorityClass(Handle(), priority) != 0); |