1// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/first_run/upgrade_util.h" 6 7#include <algorithm> 8#include <string> 9 10#include "base/base_paths.h" 11#include "base/command_line.h" 12#include "base/environment.h" 13#include "base/file_path.h" 14#include "base/file_util.h" 15#include "base/logging.h" 16#include "base/path_service.h" 17#include "base/process_util.h" 18#include "base/win/registry.h" 19#include "base/win/scoped_comptr.h" 20#include "chrome/browser/first_run/upgrade_util_win.h" 21#include "chrome/common/chrome_constants.h" 22#include "chrome/installer/util/browser_distribution.h" 23#include "chrome/installer/util/google_update_constants.h" 24#include "chrome/installer/util/install_util.h" 25#include "chrome/installer/util/shell_util.h" 26#include "chrome/installer/util/util_constants.h" 27#include "google_update_idl.h" 28 29namespace { 30 31bool GetNewerChromeFile(FilePath* path) { 32 if (!PathService::Get(base::DIR_EXE, path)) 33 return false; 34 *path = path->Append(installer::kChromeNewExe); 35 return true; 36} 37 38bool InvokeGoogleUpdateForRename() { 39 base::win::ScopedComPtr<IProcessLauncher> ipl; 40 if (!FAILED(ipl.CreateInstance(__uuidof(ProcessLauncherClass)))) { 41 ULONG_PTR phandle = NULL; 42 DWORD id = GetCurrentProcessId(); 43 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 44 if (!FAILED(ipl->LaunchCmdElevated(dist->GetAppGuid().c_str(), 45 google_update::kRegRenameCmdField, 46 id, 47 &phandle))) { 48 HANDLE handle = HANDLE(phandle); 49 WaitForSingleObject(handle, INFINITE); 50 DWORD exit_code; 51 ::GetExitCodeProcess(handle, &exit_code); 52 ::CloseHandle(handle); 53 if (exit_code == installer::RENAME_SUCCESSFUL) 54 return true; 55 } 56 } 57 return false; 58} 59 60} // namespace 61 62namespace upgrade_util { 63 64bool RelaunchChromeBrowser(const CommandLine& command_line) { 65 scoped_ptr<base::Environment> env(base::Environment::Create()); 66 env->UnSetVar(chrome::kChromeVersionEnvVar); 67 return base::LaunchApp( 68 command_line.command_line_string(), false, false, NULL); 69} 70 71bool IsUpdatePendingRestart() { 72 FilePath new_chrome_exe; 73 if (!GetNewerChromeFile(&new_chrome_exe)) 74 return false; 75 return file_util::PathExists(new_chrome_exe); 76} 77 78bool SwapNewChromeExeIfPresent() { 79 FilePath new_chrome_exe; 80 if (!GetNewerChromeFile(&new_chrome_exe)) 81 return false; 82 if (!file_util::PathExists(new_chrome_exe)) 83 return false; 84 FilePath cur_chrome_exe; 85 if (!PathService::Get(base::FILE_EXE, &cur_chrome_exe)) 86 return false; 87 88 // First try to rename exe by launching rename command ourselves. 89 bool user_install = 90 InstallUtil::IsPerUserInstall(cur_chrome_exe.value().c_str()); 91 HKEY reg_root = user_install ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; 92 BrowserDistribution *dist = BrowserDistribution::GetDistribution(); 93 base::win::RegKey key; 94 std::wstring rename_cmd; 95 if ((key.Open(reg_root, dist->GetVersionKey().c_str(), 96 KEY_READ) == ERROR_SUCCESS) && 97 (key.ReadValue(google_update::kRegRenameCmdField, 98 &rename_cmd) == ERROR_SUCCESS)) { 99 base::ProcessHandle handle; 100 if (base::LaunchApp(rename_cmd, true, true, &handle)) { 101 DWORD exit_code; 102 ::GetExitCodeProcess(handle, &exit_code); 103 ::CloseHandle(handle); 104 if (exit_code == installer::RENAME_SUCCESSFUL) 105 return true; 106 } 107 } 108 109 // Rename didn't work so try to rename by calling Google Update 110 return InvokeGoogleUpdateForRename(); 111} 112 113bool DoUpgradeTasks(const CommandLine& command_line) { 114 if (!SwapNewChromeExeIfPresent()) 115 return false; 116 // At this point the chrome.exe has been swapped with the new one. 117 if (!RelaunchChromeBrowser(command_line)) { 118 // The re-launch fails. Feel free to panic now. 119 NOTREACHED(); 120 } 121 return true; 122} 123 124} // namespace upgrade_util 125