This source file includes following definitions.
- GetNewerChromeFile
- InvokeGoogleUpdateForRename
- GetMetroRelauncherPath
- RelaunchModeEnumToString
- RelaunchModeStringToEnum
- RelaunchChromeHelper
- RelaunchChromeBrowser
- RelaunchChromeWithMode
- IsUpdatePendingRestart
- SwapNewChromeExeIfPresent
- DoUpgradeTasks
#include "chrome/browser/first_run/upgrade_util.h"
#include <windows.h>
#include <shellapi.h>
#include <algorithm>
#include <string>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "base/win/windows_version.h"
#include "chrome/browser/first_run/upgrade_util_win.h"
#include "chrome/browser/shell_integration.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/util_constants.h"
#include "google_update/google_update_idl.h"
namespace {
bool GetNewerChromeFile(base::FilePath* path) {
if (!PathService::Get(base::DIR_EXE, path))
return false;
*path = path->Append(installer::kChromeNewExe);
return true;
}
bool InvokeGoogleUpdateForRename() {
base::win::ScopedComPtr<IProcessLauncher> ipl;
if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) {
ULONG_PTR phandle = NULL;
DWORD id = GetCurrentProcessId();
BrowserDistribution* dist = BrowserDistribution::GetDistribution();
if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(),
google_update::kRegRenameCmdField,
id,
&phandle))) {
HANDLE handle = HANDLE(phandle);
WaitForSingleObject(handle, INFINITE);
DWORD exit_code;
::GetExitCodeProcess(handle, &exit_code);
::CloseHandle(handle);
if (exit_code == installer::RENAME_SUCCESSFUL)
return true;
}
}
return false;
}
base::FilePath GetMetroRelauncherPath(const base::FilePath& chrome_exe,
const std::string& version_str) {
base::FilePath path(chrome_exe.DirName());
if (!version_str.empty())
path = path.AppendASCII(version_str);
return path.Append(installer::kDelegateExecuteExe);
}
}
namespace upgrade_util {
const char kRelaunchModeMetro[] = "relaunch.mode.metro";
const char kRelaunchModeDesktop[] = "relaunch.mode.desktop";
const char kRelaunchModeDefault[] = "relaunch.mode.default";
std::string RelaunchModeEnumToString(const RelaunchMode relaunch_mode) {
if (relaunch_mode == RELAUNCH_MODE_METRO)
return kRelaunchModeMetro;
if (relaunch_mode == RELAUNCH_MODE_DESKTOP)
return kRelaunchModeDesktop;
return kRelaunchModeDefault;
}
RelaunchMode RelaunchModeStringToEnum(const std::string& relaunch_mode) {
if (relaunch_mode == kRelaunchModeMetro)
return RELAUNCH_MODE_METRO;
if (relaunch_mode == kRelaunchModeDesktop)
return RELAUNCH_MODE_DESKTOP;
return RELAUNCH_MODE_DEFAULT;
}
bool RelaunchChromeHelper(const CommandLine& command_line,
const RelaunchMode& relaunch_mode) {
scoped_ptr<base::Environment> env(base::Environment::Create());
std::string version_str;
if (env->GetVar(chrome::kChromeVersionEnvVar, &version_str))
env->UnSetVar(chrome::kChromeVersionEnvVar);
else
version_str.clear();
if (base::win::GetVersion() < base::win::VERSION_WIN8)
return base::LaunchProcess(command_line, base::LaunchOptions(), NULL);
base::FilePath chrome_exe;
if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
NOTREACHED();
return false;
}
base::string16 mutex_name =
base::StringPrintf(L"chrome.relaunch.%d", ::GetCurrentProcessId());
HANDLE mutex = ::CreateMutexW(NULL, TRUE, mutex_name.c_str());
if (!mutex) {
NOTREACHED();
return false;
}
if (::GetLastError() == ERROR_ALREADY_EXISTS) {
NOTREACHED() << "Relaunch mutex already exists";
return false;
}
CommandLine relaunch_cmd(CommandLine::NO_PROGRAM);
relaunch_cmd.AppendSwitchPath(switches::kRelaunchShortcut,
ShellIntegration::GetStartMenuShortcut(chrome_exe));
relaunch_cmd.AppendSwitchNative(switches::kWaitForMutex, mutex_name);
if (relaunch_mode != RELAUNCH_MODE_DEFAULT) {
relaunch_cmd.AppendSwitch(relaunch_mode == RELAUNCH_MODE_METRO?
switches::kForceImmersive : switches::kForceDesktop);
}
base::string16 params(relaunch_cmd.GetCommandLineString());
base::string16 path(GetMetroRelauncherPath(chrome_exe, version_str).value());
SHELLEXECUTEINFO sei = { sizeof(sei) };
sei.fMask = SEE_MASK_FLAG_LOG_USAGE | SEE_MASK_NOCLOSEPROCESS;
sei.nShow = SW_SHOWNORMAL;
sei.lpFile = path.c_str();
sei.lpParameters = params.c_str();
if (!::ShellExecuteExW(&sei)) {
NOTREACHED() << "ShellExecute failed with " << GetLastError();
return false;
}
DWORD pid = ::GetProcessId(sei.hProcess);
CloseHandle(sei.hProcess);
if (!pid)
return false;
::AllowSetForegroundWindow(pid);
return true;
}
bool RelaunchChromeBrowser(const CommandLine& command_line) {
return RelaunchChromeHelper(command_line, RELAUNCH_MODE_DEFAULT);
}
bool RelaunchChromeWithMode(const CommandLine& command_line,
const RelaunchMode& relaunch_mode) {
return RelaunchChromeHelper(command_line, relaunch_mode);
}
bool IsUpdatePendingRestart() {
base::FilePath new_chrome_exe;
if (!GetNewerChromeFile(&new_chrome_exe))
return false;
return base::PathExists(new_chrome_exe);
}
bool SwapNewChromeExeIfPresent() {
base::FilePath new_chrome_exe;
if (!GetNewerChromeFile(&new_chrome_exe))
return false;
if (!base::PathExists(new_chrome_exe))
return false;
base::FilePath cur_chrome_exe;
if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
return false;
bool user_install =
InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str());
HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
BrowserDistribution *dist = BrowserDistribution::GetDistribution();
base::win::RegKey key;
if (key.Open(reg_root, dist->GetVersionKey().c_str(),
KEY_QUERY_VALUE) == ERROR_SUCCESS) {
std::wstring rename_cmd;
if (key.ReadValue(google_update::kRegRenameCmdField,
&rename_cmd) == ERROR_SUCCESS) {
base::win::ScopedHandle handle;
base::LaunchOptions options;
options.wait = true;
options.start_hidden = true;
if (base::LaunchProcess(rename_cmd, options, &handle)) {
DWORD exit_code;
::GetExitCodeProcess(handle, &exit_code);
if (exit_code == installer::RENAME_SUCCESSFUL)
return true;
}
}
}
return InvokeGoogleUpdateForRename();
}
bool DoUpgradeTasks(const CommandLine& command_line) {
if (base::win::IsMetroProcess())
return false;
if (!SwapNewChromeExeIfPresent())
return false;
if (!RelaunchChromeBrowser(command_line)) {
NOTREACHED();
}
return true;
}
}