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
GetNewerChromeFile(FilePath * path)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
InvokeGoogleUpdateForRename()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
RelaunchChromeBrowser(const CommandLine & command_line)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
IsUpdatePendingRestart()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
SwapNewChromeExeIfPresent()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
DoUpgradeTasks(const CommandLine & command_line)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