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 29 namespace { 30 31 bool 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 38 bool 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 62 namespace upgrade_util { 63 64 bool 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 71 bool 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 78 bool 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 113 bool 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