| 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 |