15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/first_run/upgrade_util.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <psapi.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_paths.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/prefs/pref_service.h"
22bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/launch.h"
23bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/process/process_handle.h"
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/metro.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/browser_process.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/first_run/upgrade_util_win.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/shell_integration.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/pref_names.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/browser_distribution.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/google_update_constants.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/install_util.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/shell_util.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/installer/util/util_constants.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_update/google_update_idl.h"
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/base/ui_base_switches.h"
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool GetNewerChromeFile(base::FilePath* path) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::DIR_EXE, path))
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *path = path->Append(installer::kChromeNewExe);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool InvokeGoogleUpdateForRename() {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<IProcessLauncher> ipl;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ULONG_PTR phandle = NULL;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD id = GetCurrentProcessId();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       google_update::kRegRenameCmdField,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       id,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       &phandle))) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HANDLE handle = HANDLE(phandle);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      WaitForSingleObject(handle, INFINITE);
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD exit_code;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::GetExitCodeProcess(handle, &exit_code);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::CloseHandle(handle);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (exit_code == installer::RENAME_SUCCESSFUL)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)base::FilePath GetMetroRelauncherPath(const base::FilePath& chrome_exe,
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      const std::string& version_str) {
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path(chrome_exe.DirName());
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The relauncher is ordinarily in the version directory.  When running in a
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // build tree however (where CHROME_VERSION is not set in the environment)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // look for it in Chrome's directory.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!version_str.empty())
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    path = path.AppendASCII(version_str);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return path.Append(installer::kDelegateExecuteExe);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace upgrade_util {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kRelaunchModeMetro[] = "relaunch.mode.metro";
940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kRelaunchModeDesktop[] = "relaunch.mode.desktop";
950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)const char kRelaunchModeDefault[] = "relaunch.mode.default";
960f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
970f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)// TODO(shrikant): Have a map/array to quickly map enum to strings.
980f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)std::string RelaunchModeEnumToString(const RelaunchMode relaunch_mode) {
990f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (relaunch_mode == RELAUNCH_MODE_METRO)
1000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return kRelaunchModeMetro;
1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (relaunch_mode == RELAUNCH_MODE_DESKTOP)
1030f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return kRelaunchModeDesktop;
1040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // For the purpose of code flow, even in case of wrong value we will
1060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // return default re-launch mode.
1070f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return kRelaunchModeDefault;
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)RelaunchMode RelaunchModeStringToEnum(const std::string& relaunch_mode) {
1110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (relaunch_mode == kRelaunchModeMetro)
1120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return RELAUNCH_MODE_METRO;
1130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (relaunch_mode == kRelaunchModeDesktop)
1150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    return RELAUNCH_MODE_DESKTOP;
1160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // On Windows 7 if the current browser is in Chrome OS mode, then restart
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // into Chrome OS mode.
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if ((base::win::GetVersion() == base::win::VERSION_WIN7) &&
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       CommandLine::ForCurrentProcess()->HasSwitch(switches::kViewerConnect) &&
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci       g_browser_process->local_state()->HasPrefPath(prefs::kRelaunchMode)) {
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(ananta)
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // On Windows 8, the delegate execute process looks up the previously
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // launched mode from the registry and relaunches into that mode. We need
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // something similar on Windows 7. For now, set the pref to ensure that
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // we get relaunched into Chrome OS mode.
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    g_browser_process->local_state()->SetString(
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        prefs::kRelaunchMode, upgrade_util::kRelaunchModeMetro);
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return RELAUNCH_MODE_METRO;
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return RELAUNCH_MODE_DEFAULT;
1330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)}
1340f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
1350f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool RelaunchChromeHelper(const CommandLine& command_line,
1360f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                          const RelaunchMode& relaunch_mode) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string version_str;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the version variable and remove it from the environment.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env->GetVar(chrome::kChromeVersionEnvVar, &version_str))
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    env->UnSetVar(chrome::kChromeVersionEnvVar);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    version_str.clear();
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath chrome_exe;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Explicitly make sure to relaunch chrome.exe rather than old_chrome.exe.
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This can happen when old_chrome.exe is launched by a user.
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CommandLine chrome_exe_command_line = command_line;
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  chrome_exe_command_line.SetProgram(
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      chrome_exe.DirName().Append(installer::kChromeExe));
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (base::win::GetVersion() < base::win::VERSION_WIN8 &&
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      relaunch_mode != RELAUNCH_MODE_METRO &&
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      relaunch_mode != RELAUNCH_MODE_DESKTOP)
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return base::LaunchProcess(chrome_exe_command_line,
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                               base::LaunchOptions(), NULL);
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // On Windows 8 we always use the delegate_execute for re-launching chrome.
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // On Windows 7 we use delegate_execute for re-launching chrome into Windows
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // ASH.
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  //
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Pass this Chrome's Start Menu shortcut path to the relauncher so it can re-
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // activate chrome via ShellExecute which will wait until we exit. Since
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // ShellExecute does not support handle passing to the child process we create
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // a uniquely named mutex that we aquire and never release. So when we exit,
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Windows marks our mutex as abandoned and the wait is satisfied. The format
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // of the named mutex is important. See DelegateExecuteOperation for more
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // details.
175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 mutex_name =
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::StringPrintf(L"chrome.relaunch.%d", ::GetCurrentProcessId());
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE mutex = ::CreateMutexW(NULL, TRUE, mutex_name.c_str());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The |mutex| handle needs to be leaked. See comment above.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!mutex) {
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetLastError() == ERROR_ALREADY_EXISTS) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Relaunch mutex already exists";
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CommandLine relaunch_cmd(CommandLine::NO_PROGRAM);
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  relaunch_cmd.AppendSwitchPath(switches::kRelaunchShortcut,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ShellIntegration::GetStartMenuShortcut(chrome_exe));
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  relaunch_cmd.AppendSwitchNative(switches::kWaitForMutex, mutex_name);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1930f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (relaunch_mode != RELAUNCH_MODE_DEFAULT) {
1940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    relaunch_cmd.AppendSwitch(relaunch_mode == RELAUNCH_MODE_METRO?
1950f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        switches::kForceImmersive : switches::kForceDesktop);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 params(relaunch_cmd.GetCommandLineString());
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::string16 path(GetMetroRelauncherPath(chrome_exe, version_str).value());
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SHELLEXECUTEINFO sei = { sizeof(sei) };
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.fMask = SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOCLOSEPROCESS;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.nShow = SW_SHOWNORMAL;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.lpFile = path.c_str();
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sei.lpParameters = params.c_str();
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!::ShellExecuteExW(&sei)) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "ShellExecute failed with " << GetLastError();
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD pid = ::GetProcessId(sei.hProcess);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CloseHandle(sei.hProcess);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pid)
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The next call appears to be needed if we are relaunching from desktop into
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // metro mode. The observed effect if not done is that chrome starts in metro
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // mode but it is not given focus and it gets killed by windows after a few
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // seconds.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::AllowSetForegroundWindow(pid);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool RelaunchChromeBrowser(const CommandLine& command_line) {
2240f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return RelaunchChromeHelper(command_line, RELAUNCH_MODE_DEFAULT);
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)bool RelaunchChromeWithMode(const CommandLine& command_line,
2280f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)                            const RelaunchMode& relaunch_mode) {
2290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  return RelaunchChromeHelper(command_line, relaunch_mode);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool IsUpdatePendingRestart() {
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_chrome_exe;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetNewerChromeFile(&new_chrome_exe))
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return base::PathExists(new_chrome_exe);
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SwapNewChromeExeIfPresent() {
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath new_chrome_exe;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!GetNewerChromeFile(&new_chrome_exe))
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(new_chrome_exe))
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath cur_chrome_exe;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open up the registry key containing current version and rename information.
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool user_install =
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserDistribution *dist = BrowserDistribution::GetDistribution();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::RegKey key;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key.Open(reg_root, dist->GetVersionKey().c_str(),
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               KEY_QUERY_VALUE) == ERROR_SUCCESS) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // First try to rename exe by launching rename command ourselves.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::wstring rename_cmd;
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (key.ReadValue(google_update::kRegRenameCmdField,
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      &rename_cmd) == ERROR_SUCCESS) {
261f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::win::ScopedHandle handle;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::LaunchOptions options;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      options.wait = true;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      options.start_hidden = true;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (base::LaunchProcess(rename_cmd, options, &handle)) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        DWORD exit_code;
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ::GetExitCodeProcess(handle.Get(), &exit_code);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (exit_code == installer::RENAME_SUCCESSFUL)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return true;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Rename didn't work so try to rename by calling Google Update
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return InvokeGoogleUpdateForRename();
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool IsRunningOldChrome() {
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // This figures out the actual file name that the section containing the
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // mapped exe refers to. This is used instead of GetModuleFileName because the
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // .exe may have been renamed out from under us while we've been running which
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // GetModuleFileName won't notice.
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  wchar_t mapped_file_name[MAX_PATH * 2] = {};
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!::GetMappedFileName(::GetCurrentProcess(),
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           reinterpret_cast<void*>(::GetModuleHandle(NULL)),
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           mapped_file_name,
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                           arraysize(mapped_file_name))) {
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::FilePath file_name(base::FilePath(mapped_file_name).BaseName());
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return base::FilePath::CompareEqualIgnoreCase(file_name.value(),
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                installer::kChromeOldExe);
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DoUpgradeTasks(const CommandLine& command_line) {
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The DelegateExecute verb handler finalizes pending in-use updates for
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // metro mode launches, as Chrome cannot be gracefully relaunched when
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // running in this mode.
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::IsMetroProcess())
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!SwapNewChromeExeIfPresent() && !IsRunningOldChrome())
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // At this point the chrome.exe has been swapped with the new one.
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!RelaunchChromeBrowser(command_line)) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The re-launch fails. Feel free to panic now.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace upgrade_util
314