summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/chrome_installer.gypi1
-rw-r--r--chrome/installer/setup/run_all_unittests.cc7
-rw-r--r--chrome/installer/setup/setup_main.cc5
-rw-r--r--chrome/installer/setup/setup_util.cc17
-rw-r--r--chrome/installer/setup/setup_util.h5
-rw-r--r--chrome/installer/setup/setup_util_unittest.cc88
-rw-r--r--chrome/installer/setup/setup_util_unittest.h24
7 files changed, 147 insertions, 0 deletions
diff --git a/chrome/chrome_installer.gypi b/chrome/chrome_installer.gypi
index 16c4d4b..e85d7fc 100644
--- a/chrome/chrome_installer.gypi
+++ b/chrome/chrome_installer.gypi
@@ -433,6 +433,7 @@
'installer/setup/setup_unittests_resource.h',
'installer/setup/setup_util.cc',
'installer/setup/setup_util_unittest.cc',
+ 'installer/setup/setup_util_unittest.h',
],
'rules': [
{
diff --git a/chrome/installer/setup/run_all_unittests.cc b/chrome/installer/setup/run_all_unittests.cc
index 1f55d01..a309b11 100644
--- a/chrome/installer/setup/run_all_unittests.cc
+++ b/chrome/installer/setup/run_all_unittests.cc
@@ -2,12 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/command_line.h"
#include "base/test/test_suite.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/installer/setup/setup_util_unittest.h"
int main(int argc, char** argv) {
TestSuite test_suite(argc, argv);
+ // Handle the --adjust-process-priority switch, which is used to test the
+ // installer::AdjustProcessPriority() function in a subprocess.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(kAdjustProcessPriority))
+ return DoProcessPriorityAdjustment();
+
// Register Chrome Path provider so that we can get test data dir.
chrome::RegisterPathProvider();
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 70832b6..f465556 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -639,6 +639,11 @@ installer::InstallStatus InstallProductsHelper(
const bool system_install = installer_state.system_install();
installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
+ // Drop to background processing mode if the process was started below the
+ // normal process priority class.
+ bool entered_background_mode = installer::AdjustProcessPriority();
+ VLOG_IF(1, entered_background_mode) << "Entered background processing mode.";
+
// For install the default location for chrome.packed.7z is in current
// folder, so get that value first.
base::FilePath archive(cmd_line.GetProgram().DirName().Append(
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 9f112c0..55a4a8b 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -15,6 +15,7 @@
#include "base/process_util.h"
#include "base/string_util.h"
#include "base/version.h"
+#include "base/win/windows_version.h"
#include "chrome/installer/util/copy_tree_work_item.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installer_state.h"
@@ -313,6 +314,22 @@ bool WillProductBePresentAfterSetup(
return is_affected ? !is_uninstall : is_present;
}
+bool AdjustProcessPriority() {
+ if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+ DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess());
+ if (priority_class == 0) {
+ PLOG(WARNING) << "Failed to get the process's priority class.";
+ } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS ||
+ priority_class == IDLE_PRIORITY_CLASS) {
+ BOOL result = ::SetPriorityClass(::GetCurrentProcess(),
+ PROCESS_MODE_BACKGROUND_BEGIN);
+ PLOG_IF(WARNING, !result) << "Failed to enter background mode.";
+ return !!result;
+ }
+ }
+ return false;
+}
+
ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name)
: is_enabled_(false) {
if (!::OpenProcessToken(::GetCurrentProcess(),
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index cfd993f..780c883 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -81,6 +81,11 @@ bool WillProductBePresentAfterSetup(
const installer::InstallationState& machine_state,
BrowserDistribution::Type type);
+// Drops the process down to background processing mode on supported OSes if it
+// was launched below the normal process priority. Returns true when background
+// procesing mode is entered.
+bool AdjustProcessPriority();
+
// This class will enable the privilege defined by |privilege_name| on the
// current process' token. The privilege will be disabled upon the
// ScopedTokenPrivilege's destruction (unless it was already enabled when the
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 6fccc2c..c699b1b 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -2,17 +2,22 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/installer/setup/setup_util_unittest.h"
+
#include <windows.h>
#include <string>
+#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
+#include "base/process_util.h"
#include "base/threading/platform_thread.h"
#include "base/time.h"
#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/installer/setup/setup_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -189,3 +194,86 @@ TEST(SetupUtilTest, ScopedTokenPrivilegeAlreadyEnabled) {
ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege));
}
+
+const char kAdjustProcessPriority[] = "adjust-process-priority";
+
+PriorityClassChangeResult DoProcessPriorityAdjustment() {
+ return installer::AdjustProcessPriority() ? PCCR_CHANGED : PCCR_UNCHANGED;
+}
+
+namespace {
+
+// A scoper that sets/resets the current process's priority class.
+class ScopedPriorityClass {
+ public:
+ // Applies |priority_class|, returning an instance if a change was made.
+ // Otherwise, returns an empty scoped_ptr.
+ static scoped_ptr<ScopedPriorityClass> Create(DWORD priority_class);
+ ~ScopedPriorityClass();
+
+ private:
+ explicit ScopedPriorityClass(DWORD original_priority_class);
+ DWORD original_priority_class_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedPriorityClass);
+};
+
+scoped_ptr<ScopedPriorityClass> ScopedPriorityClass::Create(
+ DWORD priority_class) {
+ HANDLE this_process = ::GetCurrentProcess();
+ DWORD original_priority_class = ::GetPriorityClass(this_process);
+ EXPECT_NE(0U, original_priority_class);
+ if (original_priority_class && original_priority_class != priority_class) {
+ BOOL result = ::SetPriorityClass(this_process, priority_class);
+ EXPECT_NE(FALSE, result);
+ if (result) {
+ return scoped_ptr<ScopedPriorityClass>(
+ new ScopedPriorityClass(original_priority_class));
+ }
+ }
+ return scoped_ptr<ScopedPriorityClass>();
+}
+
+ScopedPriorityClass::ScopedPriorityClass(DWORD original_priority_class)
+ : original_priority_class_(original_priority_class) {}
+
+ScopedPriorityClass::~ScopedPriorityClass() {
+ BOOL result = ::SetPriorityClass(::GetCurrentProcess(),
+ original_priority_class_);
+ EXPECT_NE(FALSE, result);
+}
+
+PriorityClassChangeResult RelaunchAndDoProcessPriorityAdjustment() {
+ CommandLine cmd_line(*CommandLine::ForCurrentProcess());
+ cmd_line.AppendSwitch(kAdjustProcessPriority);
+ base::ProcessHandle process_handle = NULL;
+ int exit_code = 0;
+ if (!base::LaunchProcess(cmd_line, base::LaunchOptions(),
+ &process_handle)) {
+ ADD_FAILURE() << " to launch subprocess.";
+ } else if (!base::WaitForExitCode(process_handle, &exit_code)) {
+ ADD_FAILURE() << " to wait for subprocess to exit.";
+ } else {
+ return static_cast<PriorityClassChangeResult>(exit_code);
+ }
+ return PCCR_UNKNOWN;
+}
+
+} // namespace
+
+// Launching a subprocess at normal priority class is a noop.
+TEST(SetupUtilTest, AdjustFromNormalPriority) {
+ ASSERT_EQ(NORMAL_PRIORITY_CLASS, ::GetPriorityClass(::GetCurrentProcess()));
+ EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment());
+}
+
+// Launching a subprocess below normal priority class drops it to bg mode for
+// sufficiently recent operating systems.
+TEST(SetupUtilTest, AdjustFromBelowNormalPriority) {
+ scoped_ptr<ScopedPriorityClass> below_normal =
+ ScopedPriorityClass::Create(BELOW_NORMAL_PRIORITY_CLASS);
+ ASSERT_TRUE(below_normal);
+ if (base::win::GetVersion() > base::win::VERSION_SERVER_2003)
+ EXPECT_EQ(PCCR_CHANGED, RelaunchAndDoProcessPriorityAdjustment());
+ else
+ EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment());
+}
diff --git a/chrome/installer/setup/setup_util_unittest.h b/chrome/installer/setup/setup_util_unittest.h
new file mode 100644
index 0000000..a367d66
--- /dev/null
+++ b/chrome/installer/setup/setup_util_unittest.h
@@ -0,0 +1,24 @@
+// Copyright 2013 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 CHROME_INSTALLER_SETUP_SETUP_UTIL_UNITTEST_H_
+#define CHROME_INSTALLER_SETUP_SETUP_UTIL_UNITTEST_H_
+
+// A command line switch that causes the test harness to exit with the result of
+// DoProcessPriorityAdjustment rather than executing all tests.
+extern const char kAdjustProcessPriority[];
+
+// Process exit codes when the test harness is run with the
+// kAdjustProcessPriority switch.
+enum PriorityClassChangeResult {
+ PCCR_UNKNOWN,
+ PCCR_UNCHANGED,
+ PCCR_CHANGED,
+};
+
+// Calls AdjustProcessPriority() and returns PCCR_CHANGED or PCCR_UNCHANGED
+// based on its true or false result (respectively).
+PriorityClassChangeResult DoProcessPriorityAdjustment();
+
+#endif // CHROME_INSTALLER_SETUP_SETUP_UTIL_UNITTEST_H_