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 "chrome/browser/first_run/upgrade_util.h" | 5 #include "chrome/browser/first_run/upgrade_util.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <psapi.h> | 8 #include <psapi.h> |
9 #include <shellapi.h> | 9 #include <shellapi.h> |
10 | 10 |
11 #include <algorithm> | 11 #include <algorithm> |
12 #include <string> | 12 #include <string> |
13 | 13 |
14 #include "base/base_paths.h" | 14 #include "base/base_paths.h" |
15 #include "base/command_line.h" | 15 #include "base/command_line.h" |
16 #include "base/environment.h" | 16 #include "base/environment.h" |
17 #include "base/files/file_path.h" | 17 #include "base/files/file_path.h" |
18 #include "base/files/file_util.h" | 18 #include "base/files/file_util.h" |
19 #include "base/logging.h" | 19 #include "base/logging.h" |
20 #include "base/macros.h" | 20 #include "base/macros.h" |
21 #include "base/path_service.h" | 21 #include "base/path_service.h" |
22 #include "base/prefs/pref_service.h" | 22 #include "base/prefs/pref_service.h" |
23 #include "base/process/launch.h" | 23 #include "base/process/launch.h" |
24 #include "base/process/process_handle.h" | 24 #include "base/process/process_handle.h" |
25 #include "base/strings/string_number_conversions.h" | 25 #include "base/strings/string_number_conversions.h" |
26 #include "base/strings/string_util.h" | 26 #include "base/strings/string_util.h" |
27 #include "base/strings/stringprintf.h" | 27 #include "base/strings/stringprintf.h" |
28 #include "base/win/metro.h" | |
29 #include "base/win/registry.h" | 28 #include "base/win/registry.h" |
30 #include "base/win/scoped_comptr.h" | 29 #include "base/win/scoped_comptr.h" |
31 #include "base/win/windows_version.h" | 30 #include "base/win/windows_version.h" |
32 #include "chrome/browser/browser_process.h" | 31 #include "chrome/browser/browser_process.h" |
33 #include "chrome/browser/first_run/upgrade_util_win.h" | 32 #include "chrome/browser/first_run/upgrade_util_win.h" |
34 #include "chrome/browser/shell_integration.h" | 33 #include "chrome/browser/shell_integration.h" |
35 #include "chrome/common/chrome_constants.h" | 34 #include "chrome/common/chrome_constants.h" |
36 #include "chrome/common/chrome_switches.h" | 35 #include "chrome/common/chrome_switches.h" |
37 #include "chrome/common/pref_names.h" | 36 #include "chrome/common/pref_names.h" |
38 #include "chrome/installer/util/browser_distribution.h" | 37 #include "chrome/installer/util/browser_distribution.h" |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 NOTREACHED(); | 154 NOTREACHED(); |
156 return false; | 155 return false; |
157 } | 156 } |
158 | 157 |
159 // Explicitly make sure to relaunch chrome.exe rather than old_chrome.exe. | 158 // Explicitly make sure to relaunch chrome.exe rather than old_chrome.exe. |
160 // This can happen when old_chrome.exe is launched by a user. | 159 // This can happen when old_chrome.exe is launched by a user. |
161 base::CommandLine chrome_exe_command_line = command_line; | 160 base::CommandLine chrome_exe_command_line = command_line; |
162 chrome_exe_command_line.SetProgram( | 161 chrome_exe_command_line.SetProgram( |
163 chrome_exe.DirName().Append(installer::kChromeExe)); | 162 chrome_exe.DirName().Append(installer::kChromeExe)); |
164 | 163 |
165 // Relaunch directly if Chrome doesn't support Metro-mode on this platform | 164 return base::LaunchProcess(chrome_exe_command_line, base::LaunchOptions()) |
166 // unless an explicit relaunch mode was specified (e.g. for the Ash shell on | 165 .IsValid(); |
167 // Win7). | |
168 if (!base::win::IsChromeMetroSupported() && | |
169 relaunch_mode != RELAUNCH_MODE_METRO && | |
170 relaunch_mode != RELAUNCH_MODE_DESKTOP) { | |
171 return base::LaunchProcess(chrome_exe_command_line, | |
172 base::LaunchOptions()).IsValid(); | |
173 } | |
174 | |
175 // On Windows 8 we always use the delegate_execute for re-launching chrome. | |
176 // On Windows 7 we use delegate_execute for re-launching chrome into Windows | |
177 // ASH. | |
178 // | |
179 // Pass this Chrome's Start Menu shortcut path to the relauncher so it can re- | |
180 // activate chrome via ShellExecute which will wait until we exit. Since | |
181 // ShellExecute does not support handle passing to the child process we create | |
182 // a uniquely named mutex that we aquire and never release. So when we exit, | |
183 // Windows marks our mutex as abandoned and the wait is satisfied. The format | |
184 // of the named mutex is important. See DelegateExecuteOperation for more | |
185 // details. | |
186 base::string16 mutex_name = | |
187 base::StringPrintf(L"chrome.relaunch.%d", ::GetCurrentProcessId()); | |
188 HANDLE mutex = ::CreateMutexW(NULL, TRUE, mutex_name.c_str()); | |
189 // The |mutex| handle needs to be leaked. See comment above. | |
190 if (!mutex) { | |
191 NOTREACHED(); | |
192 return false; | |
193 } | |
194 if (::GetLastError() == ERROR_ALREADY_EXISTS) { | |
195 NOTREACHED() << "Relaunch mutex already exists"; | |
196 return false; | |
197 } | |
198 | |
199 base::CommandLine relaunch_cmd(base::CommandLine::NO_PROGRAM); | |
200 relaunch_cmd.AppendSwitchPath(switches::kRelaunchShortcut, | |
201 ShellIntegration::GetStartMenuShortcut(chrome_exe)); | |
202 relaunch_cmd.AppendSwitchNative(switches::kWaitForMutex, mutex_name); | |
203 | |
204 if (relaunch_mode != RELAUNCH_MODE_DEFAULT) { | |
205 relaunch_cmd.AppendSwitch(relaunch_mode == RELAUNCH_MODE_METRO? | |
206 switches::kForceImmersive : switches::kForceDesktop); | |
207 } | |
208 | |
209 base::string16 params(relaunch_cmd.GetCommandLineString()); | |
210 base::string16 path(GetMetroRelauncherPath(chrome_exe, version_str).value()); | |
211 | |
212 SHELLEXECUTEINFO sei = { sizeof(sei) }; | |
213 sei.fMask = SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOCLOSEPROCESS; | |
214 sei.nShow = SW_SHOWNORMAL; | |
215 sei.lpFile = path.c_str(); | |
216 sei.lpParameters = params.c_str(); | |
217 | |
218 if (!::ShellExecuteExW(&sei)) { | |
219 NOTREACHED() << "ShellExecute failed with " << GetLastError(); | |
220 return false; | |
221 } | |
222 DWORD pid = ::GetProcessId(sei.hProcess); | |
223 CloseHandle(sei.hProcess); | |
224 if (!pid) | |
225 return false; | |
226 // The next call appears to be needed if we are relaunching from desktop into | |
227 // metro mode. The observed effect if not done is that chrome starts in metro | |
228 // mode but it is not given focus and it gets killed by windows after a few | |
229 // seconds. | |
230 ::AllowSetForegroundWindow(pid); | |
231 return true; | |
232 } | 166 } |
233 | 167 |
234 bool RelaunchChromeBrowser(const base::CommandLine& command_line) { | 168 bool RelaunchChromeBrowser(const base::CommandLine& command_line) { |
235 return RelaunchChromeHelper(command_line, RELAUNCH_MODE_DEFAULT); | 169 return RelaunchChromeHelper(command_line, RELAUNCH_MODE_DEFAULT); |
236 } | 170 } |
237 | 171 |
238 bool RelaunchChromeWithMode(const base::CommandLine& command_line, | 172 bool RelaunchChromeWithMode(const base::CommandLine& command_line, |
239 const RelaunchMode& relaunch_mode) { | 173 const RelaunchMode& relaunch_mode) { |
240 return RelaunchChromeHelper(command_line, relaunch_mode); | 174 return RelaunchChromeHelper(command_line, relaunch_mode); |
241 } | 175 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 | 235 |
302 base::FilePath file_name(base::FilePath(mapped_file_name).BaseName()); | 236 base::FilePath file_name(base::FilePath(mapped_file_name).BaseName()); |
303 return base::FilePath::CompareEqualIgnoreCase(file_name.value(), | 237 return base::FilePath::CompareEqualIgnoreCase(file_name.value(), |
304 installer::kChromeOldExe); | 238 installer::kChromeOldExe); |
305 } | 239 } |
306 | 240 |
307 bool DoUpgradeTasks(const base::CommandLine& command_line) { | 241 bool DoUpgradeTasks(const base::CommandLine& command_line) { |
308 // The DelegateExecute verb handler finalizes pending in-use updates for | 242 // The DelegateExecute verb handler finalizes pending in-use updates for |
309 // metro mode launches, as Chrome cannot be gracefully relaunched when | 243 // metro mode launches, as Chrome cannot be gracefully relaunched when |
310 // running in this mode. | 244 // running in this mode. |
311 if (base::win::IsMetroProcess()) | |
312 return false; | |
313 if (!SwapNewChromeExeIfPresent() && !IsRunningOldChrome()) | 245 if (!SwapNewChromeExeIfPresent() && !IsRunningOldChrome()) |
314 return false; | 246 return false; |
315 // At this point the chrome.exe has been swapped with the new one. | 247 // At this point the chrome.exe has been swapped with the new one. |
316 if (!RelaunchChromeBrowser(command_line)) { | 248 if (!RelaunchChromeBrowser(command_line)) { |
317 // The re-launch fails. Feel free to panic now. | 249 // The re-launch fails. Feel free to panic now. |
318 NOTREACHED(); | 250 NOTREACHED(); |
319 } | 251 } |
320 return true; | 252 return true; |
321 } | 253 } |
322 | 254 |
323 } // namespace upgrade_util | 255 } // namespace upgrade_util |
OLD | NEW |