blob: f8fab1571bfbb34fd363673b571e1d38a1b1e9ea [file] [log] [blame]
[email protected]cec99842012-02-10 03:24:231// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]bc38c252011-04-12 21:46:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]815856722011-04-13 17:19:195#include "chrome/browser/first_run/upgrade_util.h"
[email protected]bc38c252011-04-12 21:46:576
[email protected]770c6d82012-09-06 22:21:327#include <windows.h>
robliaoa872e992017-05-18 06:36:198#include <objbase.h>
[email protected]fdbea98d2014-05-16 19:29:209#include <psapi.h>
[email protected]770c6d82012-09-06 22:21:3210#include <shellapi.h>
Robert Liaob2bc703d2017-10-17 20:52:3511#include <wrl/client.h>
[email protected]770c6d82012-09-06 22:21:3212
[email protected]bc38c252011-04-12 21:46:5713#include <algorithm>
Greg Thompsona1f95122019-01-31 22:46:4514#include <ios>
[email protected]bc38c252011-04-12 21:46:5715#include <string>
16
17#include "base/base_paths.h"
18#include "base/command_line.h"
[email protected]57999812013-02-24 05:40:5219#include "base/files/file_path.h"
thestig18dfb7a52014-08-26 10:44:0420#include "base/files/file_util.h"
[email protected]bc38c252011-04-12 21:46:5721#include "base/logging.h"
[email protected]bc38c252011-04-12 21:46:5722#include "base/path_service.h"
[email protected]d09a4ce1c2013-07-24 17:37:0223#include "base/process/launch.h"
24#include "base/process/process_handle.h"
Avi Drissman5f0fb8c2018-12-25 23:20:4925#include "base/stl_util.h"
[email protected]3ea1b182013-02-08 22:38:4126#include "base/strings/string_number_conversions.h"
[email protected]d8830562013-06-10 22:01:5427#include "base/strings/string_util.h"
[email protected]bc38c252011-04-12 21:46:5728#include "base/win/registry.h"
[email protected]770c6d82012-09-06 22:21:3229#include "base/win/windows_version.h"
ananta069fc882014-09-13 01:22:1230#include "chrome/browser/browser_process.h"
[email protected]3e087992011-04-14 22:28:1231#include "chrome/browser/first_run/upgrade_util_win.h"
[email protected]3f69d6e612012-08-03 18:52:2732#include "chrome/browser/shell_integration.h"
[email protected]80274b92011-07-15 17:20:3833#include "chrome/common/chrome_switches.h"
ananta069fc882014-09-13 01:22:1234#include "chrome/common/pref_names.h"
grt4474dad2017-02-27 21:00:4635#include "chrome/install_static/install_util.h"
[email protected]bc38c252011-04-12 21:46:5736#include "chrome/installer/util/google_update_constants.h"
[email protected]bc38c252011-04-12 21:46:5737#include "chrome/installer/util/util_constants.h"
brettwb1fc1b82016-02-02 00:19:0838#include "components/prefs/pref_service.h"
ananta069fc882014-09-13 01:22:1239#include "ui/base/ui_base_switches.h"
[email protected]bc38c252011-04-12 21:46:5740
grt235b3f092015-05-27 21:42:4841#if defined(GOOGLE_CHROME_BUILD)
42#include "google_update/google_update_idl.h"
43#endif
44
[email protected]bc38c252011-04-12 21:46:5745namespace {
46
[email protected]650b2d52013-02-10 03:41:4547bool GetNewerChromeFile(base::FilePath* path) {
Avi Drissman9098f9002018-05-04 00:11:5248 if (!base::PathService::Get(base::DIR_EXE, path))
[email protected]bc38c252011-04-12 21:46:5749 return false;
50 *path = path->Append(installer::kChromeNewExe);
51 return true;
52}
53
54bool InvokeGoogleUpdateForRename() {
grt235b3f092015-05-27 21:42:4855#if defined(GOOGLE_CHROME_BUILD)
Robert Liaob2bc703d2017-10-17 20:52:3556 Microsoft::WRL::ComPtr<IProcessLauncher> ipl;
Greg Thompsona1f95122019-01-31 22:46:4557 HRESULT hr = ::CoCreateInstance(__uuidof(ProcessLauncherClass), nullptr,
58 CLSCTX_ALL, IID_PPV_ARGS(&ipl));
59 if (FAILED(hr)) {
60 LOG(ERROR) << "CoCreate ProcessLauncherClass failed; hr = " << std::hex
61 << hr;
62 return false;
[email protected]bc38c252011-04-12 21:46:5763 }
Greg Thompsona1f95122019-01-31 22:46:4564
65 ULONG_PTR process_handle;
66 hr = ipl->LaunchCmdElevated(install_static::GetAppGuid(),
67 google_update::kRegRenameCmdField,
68 ::GetCurrentProcessId(), &process_handle);
69 if (FAILED(hr)) {
70 LOG(ERROR) << "IProcessLauncher::LaunchCmdElevated failed; hr = "
71 << std::hex << hr;
72 return false;
73 }
74
75 base::Process rename_process(
76 reinterpret_cast<base::ProcessHandle>(process_handle));
77 int exit_code;
78 if (!rename_process.WaitForExit(&exit_code)) {
79 PLOG(ERROR) << "WaitForExit of rename process failed";
80 return false;
81 }
82
83 if (exit_code != installer::RENAME_SUCCESSFUL) {
84 LOG(ERROR) << "Rename process failed with exit code " << exit_code;
85 return false;
86 }
87
88 return true;
89#else // GOOGLE_CHROME_BUILD
[email protected]bc38c252011-04-12 21:46:5790 return false;
Greg Thompsona1f95122019-01-31 22:46:4591#endif // GOOGLE_CHROME_BUILD
[email protected]bc38c252011-04-12 21:46:5792}
93
94} // namespace
95
[email protected]815856722011-04-13 17:19:1996namespace upgrade_util {
97
Greg Thompson87ee38f2019-08-09 06:00:2398bool RelaunchChromeBrowserImpl(const base::CommandLine& command_line) {
[email protected]650b2d52013-02-10 03:41:4599 base::FilePath chrome_exe;
Avi Drissman9098f9002018-05-04 00:11:52100 if (!base::PathService::Get(base::FILE_EXE, &chrome_exe)) {
[email protected]3f69d6e612012-08-03 18:52:27101 NOTREACHED();
102 return false;
103 }
104
[email protected]fdbea98d2014-05-16 19:29:20105 // Explicitly make sure to relaunch chrome.exe rather than old_chrome.exe.
106 // This can happen when old_chrome.exe is launched by a user.
avi556c05022014-12-22 23:31:43107 base::CommandLine chrome_exe_command_line = command_line;
[email protected]fdbea98d2014-05-16 19:29:20108 chrome_exe_command_line.SetProgram(
109 chrome_exe.DirName().Append(installer::kChromeExe));
110
scottmg20920cb2016-04-07 16:23:59111 // Set the working directory to the exe's directory. This avoids a handle to
112 // the version directory being kept open in the relaunched child process.
113 base::LaunchOptions launch_options;
114 launch_options.current_directory = chrome_exe.DirName();
Greg Thompson47faf202018-05-18 20:59:03115 // Give the new process the right to bring its windows to the foreground.
116 launch_options.grant_foreground_privilege = true;
scottmg20920cb2016-04-07 16:23:59117 return base::LaunchProcess(chrome_exe_command_line, launch_options).IsValid();
[email protected]815856722011-04-13 17:19:19118}
119
120bool IsUpdatePendingRestart() {
[email protected]650b2d52013-02-10 03:41:45121 base::FilePath new_chrome_exe;
[email protected]815856722011-04-13 17:19:19122 if (!GetNewerChromeFile(&new_chrome_exe))
123 return false;
[email protected]7567484142013-07-11 17:36:07124 return base::PathExists(new_chrome_exe);
[email protected]815856722011-04-13 17:19:19125}
126
[email protected]815856722011-04-13 17:19:19127bool SwapNewChromeExeIfPresent() {
grtb35a90b2016-08-30 05:34:21128 if (!IsUpdatePendingRestart())
[email protected]bc38c252011-04-12 21:46:57129 return false;
grtb35a90b2016-08-30 05:34:21130
fdoraye9c97a02016-10-04 12:05:16131 // If this is a system-level install, ask Google Update to launch an elevated
132 // process to rename Chrome executables.
Greg Thompsond2efb1f2018-08-29 06:12:54133 if (install_static::IsSystemInstall())
fdoraye9c97a02016-10-04 12:05:16134 return InvokeGoogleUpdateForRename();
[email protected]bc38c252011-04-12 21:46:57135
fdoraye9c97a02016-10-04 12:05:16136 // If this is a user-level install, directly launch a process to rename Chrome
137 // executables. Obtain the command to launch the process from the registry.
[email protected]bc38c252011-04-12 21:46:57138 base::win::RegKey key;
Greg Thompsona1f95122019-01-31 22:46:45139 auto result =
140 key.Open(HKEY_CURRENT_USER, install_static::GetClientsKeyPath().c_str(),
141 KEY_QUERY_VALUE | KEY_WOW64_32KEY);
142 if (result != ERROR_SUCCESS) {
143 ::SetLastError(result);
144 PLOG(ERROR) << "Open Clients key failed";
145 return false;
[email protected]bc38c252011-04-12 21:46:57146 }
147
Greg Thompsona1f95122019-01-31 22:46:45148 std::wstring rename_cmd;
149 result = key.ReadValue(google_update::kRegRenameCmdField, &rename_cmd);
150 if (result != ERROR_SUCCESS) {
151 ::SetLastError(result);
152 PLOG(ERROR) << "Read rename command failed";
153 return false;
154 }
155
156 base::LaunchOptions options;
157 options.wait = true;
158 options.start_hidden = true;
159 ::SetLastError(ERROR_SUCCESS);
160 base::Process process = base::LaunchProcess(rename_cmd, options);
161 if (!process.IsValid()) {
162 PLOG(ERROR) << "Launch rename process failed";
163 return false;
164 }
165
166 DWORD exit_code;
167 if (!::GetExitCodeProcess(process.Handle(), &exit_code)) {
168 PLOG(ERROR) << "GetExitCodeProcess of rename process failed";
169 return false;
170 }
171
172 if (exit_code != installer::RENAME_SUCCESSFUL) {
173 LOG(ERROR) << "Rename process failed with exit code " << exit_code;
174 return false;
175 }
176
177 return true;
[email protected]bc38c252011-04-12 21:46:57178}
179
[email protected]fdbea98d2014-05-16 19:29:20180bool IsRunningOldChrome() {
181 // This figures out the actual file name that the section containing the
182 // mapped exe refers to. This is used instead of GetModuleFileName because the
183 // .exe may have been renamed out from under us while we've been running which
184 // GetModuleFileName won't notice.
185 wchar_t mapped_file_name[MAX_PATH * 2] = {};
186
187 if (!::GetMappedFileName(::GetCurrentProcess(),
188 reinterpret_cast<void*>(::GetModuleHandle(NULL)),
Avi Drissman5f0fb8c2018-12-25 23:20:49189 mapped_file_name, base::size(mapped_file_name))) {
[email protected]fdbea98d2014-05-16 19:29:20190 return false;
191 }
192
193 base::FilePath file_name(base::FilePath(mapped_file_name).BaseName());
194 return base::FilePath::CompareEqualIgnoreCase(file_name.value(),
195 installer::kChromeOldExe);
196}
197
avi556c05022014-12-22 23:31:43198bool DoUpgradeTasks(const base::CommandLine& command_line) {
[email protected]fdbea98d2014-05-16 19:29:20199 if (!SwapNewChromeExeIfPresent() && !IsRunningOldChrome())
[email protected]bc38c252011-04-12 21:46:57200 return false;
201 // At this point the chrome.exe has been swapped with the new one.
[email protected]815856722011-04-13 17:19:19202 if (!RelaunchChromeBrowser(command_line)) {
[email protected]bc38c252011-04-12 21:46:57203 // The re-launch fails. Feel free to panic now.
204 NOTREACHED();
205 }
206 return true;
207}
208
[email protected]815856722011-04-13 17:19:19209} // namespace upgrade_util