Commit 0160d130 authored by shrike's avatar shrike Committed by Commit bot

Add support for backgrounding processes on the Mac

Added process_mac.cc with implementations of IsProcessBackgrounded() and
SetProcessBackgrounded().

BUG=460102

Originally Committed: https://crrev.com/e3bb10f7860a1d553c85293bd7d7615c0e7f0fd9
Reverted: https://crrev.com/ce6226a7ffe2c1cb7ac5f6cf34b56b8d217686b9

Review URL: https://codereview.chromium.org/989703002

Cr-Commit-Position: refs/heads/master@{#330464}
parent 32315ab5
...@@ -485,6 +485,7 @@ ...@@ -485,6 +485,7 @@
'process/process_iterator_openbsd.cc', 'process/process_iterator_openbsd.cc',
'process/process_iterator_win.cc', 'process/process_iterator_win.cc',
'process/process_linux.cc', 'process/process_linux.cc',
'process/process_mac.cc',
'process/process_metrics.cc', 'process/process_metrics.cc',
'process/process_metrics.h', 'process/process_metrics.h',
'process/process_metrics_freebsd.cc', 'process/process_metrics_freebsd.cc',
......
...@@ -41,6 +41,7 @@ source_set("process") { ...@@ -41,6 +41,7 @@ source_set("process") {
"process_iterator_openbsd.cc", "process_iterator_openbsd.cc",
"process_iterator_win.cc", "process_iterator_win.cc",
"process_linux.cc", "process_linux.cc",
"process_mac.cc",
"process_metrics.cc", "process_metrics.cc",
"process_metrics.h", "process_metrics.h",
"process_metrics_freebsd.cc", "process_metrics_freebsd.cc",
......
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -107,6 +107,24 @@ class BASE_EXPORT Process { ...@@ -107,6 +107,24 @@ class BASE_EXPORT Process {
// Same as WaitForExit() but only waits for up to |timeout|. // Same as WaitForExit() but only waits for up to |timeout|.
bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code); 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. // A process is backgrounded when it's priority is lower than normal.
// Return true if this process is backgrounded, false otherwise. // Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const; bool IsProcessBackgrounded() const;
...@@ -116,7 +134,7 @@ class BASE_EXPORT Process { ...@@ -116,7 +134,7 @@ class BASE_EXPORT Process {
// will be made "normal" - equivalent to default process priority. // will be made "normal" - equivalent to default process priority.
// Returns true if the priority was changed, false otherwise. // Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value); bool SetProcessBackgrounded(bool value);
#endif // defined(OS_MACOSX)
// Returns an integer representing the priority of a process. The meaning // Returns an integer representing the priority of a process. The meaning
// of this value is OS dependent. // of this value is OS dependent.
int GetPriority() const; int GetPriority() const;
......
// 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;
}
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
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -253,12 +253,12 @@ Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) { ...@@ -253,12 +253,12 @@ Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
return Process(handle); return Process(handle);
} }
#if !defined(OS_LINUX) #if !defined(OS_LINUX) && !defined(OS_MACOSX)
// static // static
bool Process::CanBackgroundProcesses() { bool Process::CanBackgroundProcesses() {
return false; return false;
} }
#endif // !defined(OS_LINUX) #endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsValid() const { bool Process::IsValid() const {
return process_ != kNullProcessHandle; return process_ != kNullProcessHandle;
...@@ -353,7 +353,7 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) { ...@@ -353,7 +353,7 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout); return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
} }
#if !defined(OS_LINUX) #if !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsProcessBackgrounded() const { bool Process::IsProcessBackgrounded() const {
// See SetProcessBackgrounded(). // See SetProcessBackgrounded().
DCHECK(IsValid()); DCHECK(IsValid());
...@@ -361,13 +361,13 @@ bool Process::IsProcessBackgrounded() const { ...@@ -361,13 +361,13 @@ bool Process::IsProcessBackgrounded() const {
} }
bool Process::SetProcessBackgrounded(bool value) { bool Process::SetProcessBackgrounded(bool value) {
// POSIX only allows lowering the priority of a process, so if we // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if
// were to lower it we wouldn't be able to raise it back to its initial // we were to lower the process priority we wouldn't be able to raise it back
// priority. // to its initial priority.
DCHECK(IsValid()); NOTIMPLEMENTED();
return false; return false;
} }
#endif // !defined(OS_LINUX) #endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
int Process::GetPriority() const { int Process::GetPriority() const {
DCHECK(IsValid()); DCHECK(IsValid());
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h" #include "testing/multiprocess_func_list.h"
#if defined(OS_MACOSX)
#include <mach/mach.h>
#endif // OS_MACOSX
namespace { namespace {
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -170,7 +174,19 @@ TEST_F(ProcessTest, WaitForExitWithTimeout) { ...@@ -170,7 +174,19 @@ TEST_F(ProcessTest, WaitForExitWithTimeout) {
TEST_F(ProcessTest, SetProcessBackgrounded) { TEST_F(ProcessTest, SetProcessBackgrounded) {
Process process(SpawnChild("SimpleChildProcess")); Process process(SpawnChild("SimpleChildProcess"));
int old_priority = process.GetPriority(); int old_priority = process.GetPriority();
#if defined(OS_WIN) #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)
EXPECT_TRUE(process.SetProcessBackgrounded(true)); EXPECT_TRUE(process.SetProcessBackgrounded(true));
EXPECT_TRUE(process.IsProcessBackgrounded()); EXPECT_TRUE(process.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false)); EXPECT_TRUE(process.SetProcessBackgrounded(false));
...@@ -188,7 +204,13 @@ TEST_F(ProcessTest, SetProcessBackgrounded) { ...@@ -188,7 +204,13 @@ TEST_F(ProcessTest, SetProcessBackgrounded) {
TEST_F(ProcessTest, SetProcessBackgroundedSelf) { TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
Process process = Process::Current(); Process process = Process::Current();
int old_priority = process.GetPriority(); int old_priority = process.GetPriority();
#if defined(OS_WIN) #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)
EXPECT_TRUE(process.SetProcessBackgrounded(true)); EXPECT_TRUE(process.SetProcessBackgrounded(true));
EXPECT_TRUE(process.IsProcessBackgrounded()); EXPECT_TRUE(process.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false)); EXPECT_TRUE(process.SetProcessBackgrounded(false));
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -269,7 +269,15 @@ void TerminateOnLauncherThread(bool zygote, base::Process process) { ...@@ -269,7 +269,15 @@ void TerminateOnLauncherThread(bool zygote, base::Process process) {
void SetProcessBackgroundedOnLauncherThread(base::Process process, void SetProcessBackgroundedOnLauncherThread(base::Process process,
bool background) { bool background) {
DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER); DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
#if defined(OS_MACOSX)
MachBroker* broker = MachBroker::GetInstance();
mach_port_t task_port = broker->TaskForPid(process.Pid());
if (task_port != TASK_NULL) {
process.SetProcessBackgrounded(task_port, background);
}
#else
process.SetProcessBackgrounded(background); process.SetProcessBackgrounded(background);
#endif // defined(OS_MACOSX)
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
SetChildProcessInForeground(process.Handle(), !background); SetChildProcessInForeground(process.Handle(), !background);
#endif #endif
......
// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -2211,14 +2211,15 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) { ...@@ -2211,14 +2211,15 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
return; return;
#endif // OS_WIN #endif // OS_WIN
#if defined(OS_WIN) #if defined(OS_WIN) || defined(OS_MACOSX)
// Same as below, but bound to an experiment (http://crbug.com/458594) // Same as below, but bound to an experiment (http://crbug.com/458594 on
// initially on Windows. Enabled by default in the asbence of field trials to // Windows, http://crbug.com/398103 on the Mac). Enabled by default in the
// get coverage on the perf waterfall. // absence of field trials to get coverage on the perf waterfall.
base::FieldTrial* trial = base::FieldTrial* trial =
base::FieldTrialList::Find("BackgroundRendererProcesses"); base::FieldTrialList::Find("BackgroundRendererProcesses");
if (!trial || trial->group_name() != "Disallow") if (!trial || !StartsWithASCII(trial->group_name(), "Disallow", true)) {
child_process_launcher_->SetProcessBackgrounded(backgrounded); child_process_launcher_->SetProcessBackgrounded(backgrounded);
}
#else #else
// Control the background state from the browser process, otherwise the task // Control the background state from the browser process, otherwise the task
// telling the renderer to "unbackground" itself may be preempted by other // telling the renderer to "unbackground" itself may be preempted by other
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment