summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshrike <shrike@chromium.org>2015-06-02 12:53:57 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-02 19:54:25 +0000
commit8fbe9d3eb4ab56b0be87c3c4e04bb544ede982c7 (patch)
tree1543cdc456d3f41e6ad786bcc4301ff21ee0d674
parent1460c4b34f2dbfc37f5934380f362e2193f64360 (diff)
downloadchromium_src-8fbe9d3eb4ab56b0be87c3c4e04bb544ede982c7.zip
chromium_src-8fbe9d3eb4ab56b0be87c3c4e04bb544ede982c7.tar.gz
chromium_src-8fbe9d3eb4ab56b0be87c3c4e04bb544ede982c7.tar.bz2
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 Second commit: https://crrev.com/0160d130f8a4462fa7bfb8a9924e476d31ba9a48 Second revert: https://crrev.com/93ef7cd278d450b06f4a95fad6577d05b67624aa Review URL: https://codereview.chromium.org/989703002 Cr-Commit-Position: refs/heads/master@{#332454}
-rw-r--r--base/base.gypi1
-rw-r--r--base/process/BUILD.gn1
-rw-r--r--base/process/process.h22
-rw-r--r--base/process/process_mac.cc128
-rw-r--r--base/process/process_posix.cc18
-rw-r--r--base/process/process_unittest.cc26
-rw-r--r--chrome/browser/extensions/extension_apitest.cc6
-rw-r--r--content/browser/child_process_launcher.cc10
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc18
-rw-r--r--content/public/common/content_switches.cc3
-rw-r--r--content/public/common/content_switches.h1
11 files changed, 214 insertions, 20 deletions
diff --git a/base/base.gypi b/base/base.gypi
index e65b6ad..6e2944a 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -489,6 +489,7 @@
'process/process_iterator_openbsd.cc',
'process/process_iterator_win.cc',
'process/process_linux.cc',
+ 'process/process_mac.cc',
'process/process_metrics.cc',
'process/process_metrics.h',
'process/process_metrics_freebsd.cc',
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
index e570647..814459b 100644
--- a/base/process/BUILD.gn
+++ b/base/process/BUILD.gn
@@ -41,6 +41,7 @@ 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",
diff --git a/base/process/process.h b/base/process/process.h
index 50dfef1..1559554 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -1,4 +1,4 @@
-// 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
// found in the LICENSE file.
@@ -111,6 +111,24 @@ 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;
@@ -120,7 +138,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/base/process/process_mac.cc b/base/process/process_mac.cc
new file mode 100644
index 0000000..1913cc3
--- /dev/null
+++ b/base/process/process_mac.cc
@@ -0,0 +1,128 @@
+// 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/base/process/process_posix.cc b/base/process/process_posix.cc
index bb987d0..47b0d5b 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -1,4 +1,4 @@
-// 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
// found in the LICENSE file.
@@ -255,12 +255,12 @@ Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
return Process(handle);
}
-#if !defined(OS_LINUX)
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
// static
bool Process::CanBackgroundProcesses() {
return false;
}
-#endif // !defined(OS_LINUX)
+#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsValid() const {
return process_ != kNullProcessHandle;
@@ -355,7 +355,7 @@ bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
}
-#if !defined(OS_LINUX)
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
bool Process::IsProcessBackgrounded() const {
// See SetProcessBackgrounded().
DCHECK(IsValid());
@@ -363,13 +363,13 @@ bool Process::IsProcessBackgrounded() const {
}
bool Process::SetProcessBackgrounded(bool value) {
- // POSIX only allows lowering the priority of a process, so if we
- // were to lower it we wouldn't be able to raise it back to its initial
- // priority.
- DCHECK(IsValid());
+ // 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.
+ NOTIMPLEMENTED();
return false;
}
-#endif // !defined(OS_LINUX)
+#endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
int Process::GetPriority() const {
DCHECK(IsValid());
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index ba8e4e6..e094c03 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -11,6 +11,10 @@
#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)
@@ -170,7 +174,19 @@ TEST_F(ProcessTest, WaitForExitWithTimeout) {
TEST_F(ProcessTest, SetProcessBackgrounded) {
Process process(SpawnChild("SimpleChildProcess"));
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.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false));
@@ -188,7 +204,13 @@ TEST_F(ProcessTest, SetProcessBackgrounded) {
TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
Process process = Process::Current();
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.IsProcessBackgrounded());
EXPECT_TRUE(process.SetProcessBackgrounded(false));
diff --git a/chrome/browser/extensions/extension_apitest.cc b/chrome/browser/extensions/extension_apitest.cc
index c2e3139..c370197 100644
--- a/chrome/browser/extensions/extension_apitest.cc
+++ b/chrome/browser/extensions/extension_apitest.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/extension_apitest.h"
+#include "base/base_switches.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -14,6 +15,7 @@
#include "chrome/browser/ui/extensions/app_launch_params.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/content_switches.h"
#include "extensions/browser/api/test/test_api.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_system.h"
@@ -421,4 +423,8 @@ bool ExtensionApiTest::StartSpawnedTestServer() {
void ExtensionApiTest::SetUpCommandLine(base::CommandLine* command_line) {
ExtensionBrowserTest::SetUpCommandLine(command_line);
test_data_dir_ = test_data_dir_.AppendASCII("api_test");
+ // Backgrounded renderer processes run at a lower priority, causing the
+ // tests to take more time to complete. Disable backgrounding so that the
+ // tests don't time out.
+ command_line->AppendSwitch(switches::kDisableRendererBackgrounding);
}
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 28be72b..23cf832 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -1,4 +1,4 @@
-// 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
// found in the LICENSE file.
@@ -269,7 +269,15 @@ void TerminateOnLauncherThread(bool zygote, base::Process process) {
void SetProcessBackgroundedOnLauncherThread(base::Process process,
bool background) {
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);
+#endif // defined(OS_MACOSX)
#if defined(OS_ANDROID)
SetChildProcessInForeground(process.Handle(), !background);
#endif
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 8f90764..11812f8 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1,4 +1,4 @@
-// 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
// found in the LICENSE file.
@@ -2218,6 +2218,11 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
if (backgrounded_ && audio_renderer_host_->HasActiveAudio())
return;
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kDisableRendererBackgrounding))
+ return;
+
#if defined(OS_WIN)
// The cbstext.dll loads as a global GetMessage hook in the browser process
// and intercepts/unintercepts the kernel32 API SetPriorityClass in a
@@ -2229,14 +2234,15 @@ void RenderProcessHostImpl::SetBackgrounded(bool backgrounded) {
return;
#endif // OS_WIN
-#if defined(OS_WIN)
- // Same as below, but bound to an experiment (http://crbug.com/458594)
- // initially on Windows. Enabled by default in the asbence of field trials to
- // get coverage on the perf waterfall.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ // Same as below, but bound to an experiment (http://crbug.com/458594 on
+ // Windows, http://crbug.com/398103 on the Mac). Enabled by default in the
+ // absence of field trials to get coverage on the perf waterfall.
base::FieldTrial* trial =
base::FieldTrialList::Find("BackgroundRendererProcesses");
- if (!trial || trial->group_name() != "Disallow")
+ if (!trial || !StartsWithASCII(trial->group_name(), "Disallow", true)) {
child_process_launcher_->SetProcessBackgrounded(backgrounded);
+ }
#else
// Control the background state from the browser process, otherwise the task
// telling the renderer to "unbackground" itself may be preempted by other
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 04fd6e8b..f7c94dd 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -226,6 +226,9 @@ const char kDisableRemoteFonts[] = "disable-remote-fonts";
// Turns off the accessibility in the renderer.
const char kDisableRendererAccessibility[] = "disable-renderer-accessibility";
+// Prevent renderer process backgrounding when set.
+const char kDisableRendererBackgrounding[] = "disable-renderer-backgrounding";
+
// Disable the seccomp filter sandbox (seccomp-bpf) (Linux only).
const char kDisableSeccompFilterSandbox[] = "disable-seccomp-filter-sandbox";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index c036949..ce84514 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -76,6 +76,7 @@ CONTENT_EXPORT extern const char kDisablePluginsDiscovery[];
CONTENT_EXPORT extern const char kDisableReadingFromCanvas[];
extern const char kDisableRemoteFonts[];
extern const char kDisableRendererAccessibility[];
+CONTENT_EXPORT extern const char kDisableRendererBackgrounding[];
CONTENT_EXPORT extern const char kDisableSeccompFilterSandbox[];
CONTENT_EXPORT extern const char kDisableSetuidSandbox[];
CONTENT_EXPORT extern const char kDisableSharedWorkers[];