diff options
-rw-r--r-- | chrome/chrome_installer.gypi | 1 | ||||
-rw-r--r-- | chrome/installer/setup/run_all_unittests.cc | 7 | ||||
-rw-r--r-- | chrome/installer/setup/setup_main.cc | 5 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.cc | 17 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util.h | 5 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util_unittest.cc | 88 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util_unittest.h | 24 |
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_ |