| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cloud_print/service/win/chrome_launcher.h" | 5 #include "cloud_print/service/win/chrome_launcher.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/file_util.h" | |
| 9 #include "base/path_service.h" | |
| 10 #include "base/process.h" | 8 #include "base/process.h" |
| 11 #include "base/process_util.h" | 9 #include "base/process_util.h" |
| 12 #include "base/win/registry.h" | |
| 13 #include "base/win/scoped_handle.h" | 10 #include "base/win/scoped_handle.h" |
| 14 #include "base/win/scoped_process_information.h" | 11 #include "base/win/scoped_process_information.h" |
| 12 #include "chrome/installer/launcher_support/chrome_launcher_support.h" |
| 15 #include "cloud_print/service/service_switches.h" | 13 #include "cloud_print/service/service_switches.h" |
| 16 | 14 |
| 17 namespace { | 15 namespace { |
| 18 | 16 |
| 19 const wchar_t kChromeRegClientStateKey[] = | |
| 20 L"Software\\Google\\Update\\ClientState\\" | |
| 21 L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; | |
| 22 | |
| 23 const wchar_t kGoogleChromeExePath[] = | |
| 24 L"Google\\Chrome\\Application\\chrome.exe"; | |
| 25 | |
| 26 const wchar_t kUninstallStringField[] = L"UninstallString"; | |
| 27 | |
| 28 const wchar_t kChromeExe[] = L"chrome.exe"; | |
| 29 | |
| 30 const int kShutdownTimeoutMs = 30 * 1000; | 17 const int kShutdownTimeoutMs = 30 * 1000; |
| 31 | 18 |
| 32 void ShutdownChrome(HANDLE process, DWORD thread_id) { | 19 void ShutdownChrome(HANDLE process, DWORD thread_id) { |
| 33 if (::PostThreadMessage(thread_id, WM_QUIT, 0, 0) && | 20 if (::PostThreadMessage(thread_id, WM_QUIT, 0, 0) && |
| 34 WAIT_OBJECT_0 == ::WaitForSingleObject(process, kShutdownTimeoutMs)) { | 21 WAIT_OBJECT_0 == ::WaitForSingleObject(process, kShutdownTimeoutMs)) { |
| 35 return; | 22 return; |
| 36 } | 23 } |
| 37 LOG(ERROR) << "Failed to shutdown process."; | 24 LOG(ERROR) << "Failed to shutdown process."; |
| 38 base::KillProcess(process, 0, true); | 25 base::KillProcess(process, 0, true); |
| 39 } | 26 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 55 | 42 |
| 56 if (process_handle) | 43 if (process_handle) |
| 57 *process_handle = process_info.TakeProcessHandle(); | 44 *process_handle = process_info.TakeProcessHandle(); |
| 58 | 45 |
| 59 if (thread_id) | 46 if (thread_id) |
| 60 *thread_id = process_info.thread_id(); | 47 *thread_id = process_info.thread_id(); |
| 61 | 48 |
| 62 return true; | 49 return true; |
| 63 } | 50 } |
| 64 | 51 |
| 65 FilePath GetAnyChromePath() { | |
| 66 FilePath chrome_path = ChromeLauncher::GetChromePath(HKEY_LOCAL_MACHINE); | |
| 67 if (!chrome_path.empty()) | |
| 68 return chrome_path; | |
| 69 chrome_path = ChromeLauncher::GetChromePath(HKEY_CURRENT_USER); | |
| 70 if (!chrome_path.empty()) | |
| 71 return chrome_path; | |
| 72 if (PathService::Get(base::DIR_PROGRAM_FILES, &chrome_path)) { | |
| 73 chrome_path.Append(kGoogleChromeExePath); | |
| 74 if (file_util::PathExists(chrome_path)) | |
| 75 return chrome_path; | |
| 76 } | |
| 77 return FilePath(); | |
| 78 } | |
| 79 | |
| 80 } // namespace | 52 } // namespace |
| 81 | 53 |
| 82 ChromeLauncher::ChromeLauncher(const FilePath& user_data) | 54 ChromeLauncher::ChromeLauncher(const FilePath& user_data) |
| 83 : stop_event_(true, true), | 55 : stop_event_(true, true), |
| 84 user_data_(user_data) { | 56 user_data_(user_data) { |
| 85 } | 57 } |
| 86 | 58 |
| 87 ChromeLauncher::~ChromeLauncher() { | 59 ChromeLauncher::~ChromeLauncher() { |
| 88 } | 60 } |
| 89 | 61 |
| 90 bool ChromeLauncher::Start() { | 62 bool ChromeLauncher::Start() { |
| 91 stop_event_.Reset(); | 63 stop_event_.Reset(); |
| 92 thread_.reset(new base::DelegateSimpleThread(this, "chrome_launcher")); | 64 thread_.reset(new base::DelegateSimpleThread(this, "chrome_launcher")); |
| 93 thread_->Start(); | 65 thread_->Start(); |
| 94 return true; | 66 return true; |
| 95 } | 67 } |
| 96 | 68 |
| 97 void ChromeLauncher::Stop() { | 69 void ChromeLauncher::Stop() { |
| 98 stop_event_.Signal(); | 70 stop_event_.Signal(); |
| 99 thread_->Join(); | 71 thread_->Join(); |
| 100 thread_.reset(); | 72 thread_.reset(); |
| 101 } | 73 } |
| 102 | 74 |
| 103 void ChromeLauncher::Run() { | 75 void ChromeLauncher::Run() { |
| 104 const base::TimeDelta default_time_out = base::TimeDelta::FromSeconds(1); | 76 const base::TimeDelta default_time_out = base::TimeDelta::FromSeconds(1); |
| 105 const base::TimeDelta max_time_out = base::TimeDelta::FromHours(1); | 77 const base::TimeDelta max_time_out = base::TimeDelta::FromHours(1); |
| 106 | 78 |
| 107 for (base::TimeDelta time_out = default_time_out;; | 79 for (base::TimeDelta time_out = default_time_out;; |
| 108 time_out = std::min(time_out * 2, max_time_out)) { | 80 time_out = std::min(time_out * 2, max_time_out)) { |
| 109 FilePath chrome_path = GetAnyChromePath(); | 81 FilePath chrome_path = chrome_launcher_support::GetAnyChromePath(); |
| 110 | 82 |
| 111 if (!chrome_path.empty()) { | 83 if (!chrome_path.empty()) { |
| 112 CommandLine cmd(chrome_path); | 84 CommandLine cmd(chrome_path); |
| 113 cmd.AppendSwitchASCII(kChromeTypeSwitch, "service"); | 85 cmd.AppendSwitchASCII(kChromeTypeSwitch, "service"); |
| 114 cmd.AppendSwitchPath(kUserDataDirSwitch, user_data_); | 86 cmd.AppendSwitchPath(kUserDataDirSwitch, user_data_); |
| 115 base::win::ScopedHandle chrome_handle; | 87 base::win::ScopedHandle chrome_handle; |
| 116 base::Time started = base::Time::Now(); | 88 base::Time started = base::Time::Now(); |
| 117 DWORD thread_id = 0; | 89 DWORD thread_id = 0; |
| 118 LaunchProcess(cmd, chrome_handle.Receive(), &thread_id); | 90 LaunchProcess(cmd, chrome_handle.Receive(), &thread_id); |
| 119 int exit_code = 0; | 91 int exit_code = 0; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 131 if (base::Time::Now() - started > base::TimeDelta::FromHours(1)) { | 103 if (base::Time::Now() - started > base::TimeDelta::FromHours(1)) { |
| 132 // Reset timeout because process worked long enough. | 104 // Reset timeout because process worked long enough. |
| 133 time_out = default_time_out; | 105 time_out = default_time_out; |
| 134 } | 106 } |
| 135 } | 107 } |
| 136 if (stop_event_.TimedWait(time_out)) | 108 if (stop_event_.TimedWait(time_out)) |
| 137 break; | 109 break; |
| 138 } | 110 } |
| 139 } | 111 } |
| 140 | 112 |
| 141 FilePath ChromeLauncher::GetChromePath(HKEY key) { | |
| 142 using base::win::RegKey; | |
| 143 RegKey reg_key(key, kChromeRegClientStateKey, KEY_QUERY_VALUE); | |
| 144 | 113 |
| 145 FilePath chrome_exe_path; | |
| 146 | |
| 147 if (reg_key.Valid()) { | |
| 148 // Now grab the uninstall string from the appropriate ClientState key | |
| 149 // and use that as the base for a path to chrome.exe. | |
| 150 string16 uninstall; | |
| 151 if (reg_key.ReadValue(kUninstallStringField, &uninstall) == ERROR_SUCCESS) { | |
| 152 // The uninstall path contains the path to setup.exe which is two levels | |
| 153 // down from chrome.exe. Move up two levels (plus one to drop the file | |
| 154 // name) and look for chrome.exe from there. | |
| 155 FilePath uninstall_path(uninstall); | |
| 156 chrome_exe_path = | |
| 157 uninstall_path.DirName().DirName().DirName().Append(kChromeExe); | |
| 158 if (!file_util::PathExists(chrome_exe_path)) { | |
| 159 // By way of mild future proofing, look up one to see if there's a | |
| 160 // chrome.exe in the version directory | |
| 161 chrome_exe_path = | |
| 162 uninstall_path.DirName().DirName().Append(kChromeExe); | |
| 163 } | |
| 164 } | |
| 165 } | |
| 166 | |
| 167 if (file_util::PathExists(chrome_exe_path)) | |
| 168 return chrome_exe_path; | |
| 169 | |
| 170 return FilePath(); | |
| 171 } | |
| 172 | |
| OLD | NEW |