// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/first_run/upgrade_util.h"
#include <algorithm>
#include <string>
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/win/registry.h"
#include "base/win/scoped_comptr.h"
#include "chrome/browser/first_run/upgrade_util_win.h"
#include "chrome/common/chrome_constants.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_idl.h"
namespace {
bool GetNewerChromeFile(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;
}
} // namespace
namespace upgrade_util {
bool RelaunchChromeBrowser(const CommandLine& command_line) {
scoped_ptr<base::Environment> env(base::Environment::Create());
env->UnSetVar(chrome::kChromeVersionEnvVar);
return base::LaunchApp(
command_line.command_line_string(), false, false, NULL);
}
bool IsUpdatePendingRestart() {
FilePath new_chrome_exe;
if (!GetNewerChromeFile(&new_chrome_exe))
return false;
return file_util::PathExists(new_chrome_exe);
}
bool SwapNewChromeExeIfPresent() {
FilePath new_chrome_exe;
if (!GetNewerChromeFile(&new_chrome_exe))
return false;
if (!file_util::PathExists(new_chrome_exe))
return false;
FilePath cur_chrome_exe;
if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe))
return false;
// First try to rename exe by launching rename command ourselves.
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;
std::wstring rename_cmd;
if ((key.Open(reg_root, dist->GetVersionKey().c_str(),
KEY_READ) == ERROR_SUCCESS) &&
(key.ReadValue(google_update::kRegRenameCmdField,
&rename_cmd) == ERROR_SUCCESS)) {
base::ProcessHandle handle;
if (base::LaunchApp(rename_cmd, true, true, &handle)) {
DWORD exit_code;
::GetExitCodeProcess(handle, &exit_code);
::CloseHandle(handle);
if (exit_code == installer::RENAME_SUCCESSFUL)
return true;
}
}
// Rename didn't work so try to rename by calling Google Update
return InvokeGoogleUpdateForRename();
}
bool DoUpgradeTasks(const CommandLine& command_line) {
if (!SwapNewChromeExeIfPresent())
return false;
// At this point the chrome.exe has been swapped with the new one.
if (!RelaunchChromeBrowser(command_line)) {
// The re-launch fails. Feel free to panic now.
NOTREACHED();
}
return true;
}
} // namespace upgrade_util