Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(101)

Side by Side Diff: chrome/installer/setup/setup_util.cc

Issue 2589753002: Remove multi-install from chrome/installer/setup. (Closed)
Patch Set: gab and robertshield comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // This file declares util functions for setup project. 5 // This file declares util functions for setup project.
6 6
7 #include "chrome/installer/setup/setup_util.h" 7 #include "chrome/installer/setup/setup_util.h"
8 8
9 #include <windows.h> 9 #include <windows.h>
10 #include <stddef.h> 10 #include <stddef.h>
(...skipping 24 matching lines...) Expand all
35 #include "base/win/windows_version.h" 35 #include "base/win/windows_version.h"
36 #include "chrome/installer/setup/installer_state.h" 36 #include "chrome/installer/setup/installer_state.h"
37 #include "chrome/installer/setup/setup_constants.h" 37 #include "chrome/installer/setup/setup_constants.h"
38 #include "chrome/installer/setup/user_hive_visitor.h" 38 #include "chrome/installer/setup/user_hive_visitor.h"
39 #include "chrome/installer/util/app_registration_data.h" 39 #include "chrome/installer/util/app_registration_data.h"
40 #include "chrome/installer/util/google_update_constants.h" 40 #include "chrome/installer/util/google_update_constants.h"
41 #include "chrome/installer/util/install_util.h" 41 #include "chrome/installer/util/install_util.h"
42 #include "chrome/installer/util/installation_state.h" 42 #include "chrome/installer/util/installation_state.h"
43 #include "chrome/installer/util/master_preferences.h" 43 #include "chrome/installer/util/master_preferences.h"
44 #include "chrome/installer/util/master_preferences_constants.h" 44 #include "chrome/installer/util/master_preferences_constants.h"
45 #include "chrome/installer/util/non_updating_app_registration_data.h"
46 #include "chrome/installer/util/updating_app_registration_data.h"
45 #include "chrome/installer/util/util_constants.h" 47 #include "chrome/installer/util/util_constants.h"
46 #include "courgette/courgette.h" 48 #include "courgette/courgette.h"
47 #include "courgette/third_party/bsdiff/bsdiff.h" 49 #include "courgette/third_party/bsdiff/bsdiff.h"
48 50
49 namespace installer { 51 namespace installer {
50 52
51 namespace { 53 namespace {
52 54
53 // Event log providers registry location. 55 // Event log providers registry location.
54 constexpr wchar_t kEventLogProvidersRegPath[] = 56 constexpr wchar_t kEventLogProvidersRegPath[] =
55 L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"; 57 L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\";
56 58
57 // TODO(grt): use install_static::InstallDetails::Get().install_full_name() when 59 // TODO(grt): use install_static::InstallDetails::Get().install_full_name() when
58 // InstallDetails is initialized in the installer. 60 // InstallDetails is initialized in the installer.
59 base::string16 InstallFullName() { 61 base::string16 InstallFullName() {
60 #if defined(GOOGLE_CHROME_BUILD) 62 #if defined(GOOGLE_CHROME_BUILD)
61 base::string16 reg_path(L"Chrome"); 63 base::string16 reg_path(L"Chrome");
62 if (InstallUtil::IsChromeSxSProcess()) 64 if (InstallUtil::IsChromeSxSProcess())
63 reg_path.append(L" SxS"); 65 reg_path.append(L" SxS");
64 return reg_path; 66 return reg_path;
65 #else 67 #else
66 return base::string16(L"Chromium"); 68 return base::string16(L"Chromium");
67 #endif 69 #endif
68 } 70 }
69 71
70 // Returns true if product |type| cam be meaningfully installed without the
71 // --multi-install flag.
72 bool SupportsSingleInstall(BrowserDistribution::Type type) {
73 return (type == BrowserDistribution::CHROME_BROWSER ||
74 type == BrowserDistribution::CHROME_FRAME);
75 }
76
77 // Returns true if the "lastrun" value in |root|\|key_path| (a path to Chrome's 72 // Returns true if the "lastrun" value in |root|\|key_path| (a path to Chrome's
78 // ClientState key for a user) indicates that Chrome has been used within the 73 // ClientState key for a user) indicates that Chrome has been used within the
79 // last 28 days. 74 // last 28 days.
80 bool IsActivelyUsedIn(HKEY root, const wchar_t* key_path) { 75 bool IsActivelyUsedIn(HKEY root, const wchar_t* key_path) {
81 // This duplicates some logic in GoogleUpdateSettings::GetLastRunTime, which 76 // This duplicates some logic in GoogleUpdateSettings::GetLastRunTime, which
82 // is suitable for use from the context of Chrome but not from the installer 77 // is suitable for use from the context of Chrome but not from the installer
83 // because it was implemented with the assumption that 78 // because it was implemented with the assumption that
84 // BrowserDistribution::GetDistribution() will always be the right thing. 79 // BrowserDistribution::GetDistribution() will always be the right thing.
85 // This is true in Chrome, but not in the installer in a multi-install world. 80 // This is true in Chrome, but not in the installer in a multi-install world.
86 // Once multi-install goes away, this assumption will once again become true 81 // Once multi-install goes away, this assumption will once again become true
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 const wchar_t* user_sid, 120 const wchar_t* user_sid,
126 base::win::RegKey* user_hive) { 121 base::win::RegKey* user_hive) {
127 // Continue the iteration if this hive isn't owned by an active Chrome user. 122 // Continue the iteration if this hive isn't owned by an active Chrome user.
128 if (!IsActivelyUsedIn(user_hive->Handle(), client_state_path.c_str())) 123 if (!IsActivelyUsedIn(user_hive->Handle(), client_state_path.c_str()))
129 return true; 124 return true;
130 // Stop the iteration. 125 // Stop the iteration.
131 *is_used = true; 126 *is_used = true;
132 return false; 127 return false;
133 } 128 }
134 129
130 // "The binaries" once referred to the on-disk footprint of Chrome and/or Chrome
131 // Frame when the products were configured to share such on-disk bits. Support
132 // for this mode of install was dropped from ToT in December 2016. Remove any
133 // stray bits in the registry leftover from such installs.
134 void RemoveBinariesVersionKey(const InstallerState& installer_state) {
135 #if defined(GOOGLE_CHROME_BUILD)
136 UpdatingAppRegistrationData reg_data(
137 L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}");
138 #else
139 NonUpdatingAppRegistrationData reg_data(L"Software\\Chromium Binaries");
140 #endif
141
142 base::string16 path(reg_data.GetVersionKey());
143 if (base::win::RegKey(installer_state.root_key(), path.c_str(),
144 KEY_QUERY_VALUE | KEY_WOW64_32KEY)
145 .Valid()) {
146 const bool success = InstallUtil::DeleteRegistryKey(
huangs 2017/01/06 17:57:18 NIT: const usage for |success| (here and below) is
grt (UTC plus 2) 2017/01/06 21:15:47 Done.
147 installer_state.root_key(), path, KEY_WOW64_32KEY);
148 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteBinariesClientsKey", success);
149 }
150 }
151
152 // Remove leftover traces of multi-install Chrome Frame, if present. Once upon a
153 // time, Google Chrome Frame could be co-installed with Chrome such that they
154 // shared the same binaries on disk. Support for new installs of GCF was dropped
155 // from ToT in December 2013. Remove any stray bits in the registry leftover
156 // from an old multi-install GCF.
157 void RemoveMultiChromeFrame(const InstallerState& installer_state) {
158 // There never was a "Chromium Frame".
159 #if defined(GOOGLE_CHROME_BUILD)
160 // To maximize cleanup, unconditionally delete GCF's Clients and ClientState
161 // keys unless single-install GCF is present. This condition is satisfied if
162 // both keys exist, Clients\pv contains a value, and
163 // ClientState\UninstallString contains a path including "\Chrome
huangs 2017/01/06 17:57:18 NIT: Fix comment spacing re. "\Chrome Frame\".
grt (UTC plus 2) 2017/01/06 21:15:47 Would you believe that my editor was written by pe
164 // Frame\". Multi-install GCF would have had "\Chrome\", and anything else is
165 // garbage.
166
167 UpdatingAppRegistrationData gcf_data(
168 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}");
169 base::win::RegKey clients_key;
170 base::win::RegKey client_state_key;
171
172 bool has_clients_key =
173 clients_key.Open(installer_state.root_key(),
174 gcf_data.GetVersionKey().c_str(),
175 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS;
176 bool has_client_state_key =
177 client_state_key.Open(installer_state.root_key(),
178 gcf_data.GetStateKey().c_str(),
179 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS;
180 if (!has_clients_key && !has_client_state_key)
181 return; // Nothing to check or to clean.
182
183 base::string16 value;
184 if (has_clients_key && has_client_state_key &&
185 clients_key.ReadValue(google_update::kRegVersionField, &value) ==
186 ERROR_SUCCESS &&
187 !value.empty() &&
188 client_state_key.ReadValue(kUninstallStringField, &value) ==
189 ERROR_SUCCESS &&
190 value.find(L"\\Chrome Frame\\") != base::string16::npos) {
191 return; // Single-install Chrome Frame found.
192 }
193
194 // Remnants of multi-install GCF or of a malformed GCF are present. Remove the
195 // Clients and ClientState keys so that Google Update ceases to check for
196 // updates, and the Programs and Features control panel entry to reduce user
197 // confusion.
198 client_state_key.Close();
huangs 2017/01/06 17:57:18 NIT: Should these appear before the big comment?
grt (UTC plus 2) 2017/01/06 21:15:47 Done.
199 clients_key.Close();
200
201 constexpr int kOperations = 3;
202 int success_count = 0;
203
204 if (InstallUtil::DeleteRegistryKey(installer_state.root_key(),
205 gcf_data.GetVersionKey(),
206 KEY_WOW64_32KEY)) {
207 ++success_count;
208 }
209 if (InstallUtil::DeleteRegistryKey(installer_state.root_key(),
210 gcf_data.GetStateKey(), KEY_WOW64_32KEY)) {
211 ++success_count;
212 }
213 if (InstallUtil::DeleteRegistryKey(
214 installer_state.root_key(),
215 L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
216 L"Google Chrome Frame",
217 KEY_WOW64_32KEY)) {
218 ++success_count;
219 }
220 DCHECK_LE(success_count, kOperations);
221
222 // Used for a histogram; do not reorder.
223 enum MultiChromeFrameRemovalResult {
224 ALL_FAILED = 0,
225 PARTIAL_SUCCESS = 1,
226 SUCCESS = 2,
227 NUM_RESULTS
228 };
229 MultiChromeFrameRemovalResult result =
230 (success_count == kOperations ? SUCCESS : (success_count ? PARTIAL_SUCCESS
231 : ALL_FAILED));
232 UMA_HISTOGRAM_ENUMERATION("Setup.Install.MultiChromeFrameRemoved", result,
233 NUM_RESULTS);
234 #endif
huangs 2017/01/06 17:57:18 #endif // GOOGLE_CHROME_BUILD Same below.
grt (UTC plus 2) 2017/01/06 21:15:47 Done.
235 }
236
237 void RemoveAppLauncherVersionKey(const InstallerState& installer_state) {
238 // The app launcher was only registered for Google Chrome.
239 #if defined(GOOGLE_CHROME_BUILD)
240 UpdatingAppRegistrationData reg_data(
241 L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}");
242
243 base::string16 path(reg_data.GetVersionKey());
244 if (base::win::RegKey(installer_state.root_key(), path.c_str(),
245 KEY_QUERY_VALUE | KEY_WOW64_32KEY)
246 .Valid()) {
247 const bool succeeded = InstallUtil::DeleteRegistryKey(
248 installer_state.root_key(), path, KEY_WOW64_32KEY);
249 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteAppLauncherClientsKey",
250 succeeded);
251 }
252 #endif // GOOGLE_CHROME_BUILD
253 }
254
255 void RemoveAppHostExe(const InstallerState& installer_state) {
256 // The app host was only installed for Google Chrome.
257 #if defined(GOOGLE_CHROME_BUILD)
258 base::FilePath app_host(
259 installer_state.target_path().Append(FILE_PATH_LITERAL("app_host.exe")));
260
261 if (base::PathExists(app_host)) {
262 const bool succeeded = base::DeleteFile(app_host, false);
263 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteAppHost", succeeded);
264 }
265 #endif
266 }
267
268 void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) {
269 // These app commands were only registered for Google Chrome.
270 #if defined(GOOGLE_CHROME_BUILD)
271 base::string16 path(GetRegistrationDataCommandKey(
272 installer_state.product().distribution()->GetAppRegistrationData(),
273 L"install-extension"));
274
275 if (base::win::RegKey(installer_state.root_key(), path.c_str(),
276 KEY_QUERY_VALUE | KEY_WOW64_32KEY)
277 .Valid()) {
278 const bool succeeded = InstallUtil::DeleteRegistryKey(
279 installer_state.root_key(), path, KEY_WOW64_32KEY);
280 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteInstallExtensionCommand",
281 succeeded);
282 }
283 #endif
284 }
285
135 } // namespace 286 } // namespace
136 287
137 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; 288 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus";
138 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS"; 289 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS";
139 290
140 int CourgettePatchFiles(const base::FilePath& src, 291 int CourgettePatchFiles(const base::FilePath& src,
141 const base::FilePath& patch, 292 const base::FilePath& patch,
142 const base::FilePath& dest) { 293 const base::FilePath& dest) {
143 VLOG(1) << "Applying Courgette patch " << patch.value() 294 VLOG(1) << "Applying Courgette patch " << patch.value()
144 << " to file " << src.value() 295 << " to file " << src.value()
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 PLOG(ERROR) << "VirtualAllocEx"; 446 PLOG(ERROR) << "VirtualAllocEx";
296 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0)); 447 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0));
297 } 448 }
298 ::CloseHandle(pi.hThread); 449 ::CloseHandle(pi.hThread);
299 ::CloseHandle(pi.hProcess); 450 ::CloseHandle(pi.hProcess);
300 } 451 }
301 452
302 return ok != FALSE; 453 return ok != FALSE;
303 } 454 }
304 455
305 // There are 4 disjoint cases => return values {false,true}:
306 // (1) Product is being uninstalled => false.
307 // (2) Product is being installed => true.
308 // (3) Current operation ignores product, product is absent => false.
309 // (4) Current operation ignores product, product is present => true.
310 bool WillProductBePresentAfterSetup(
311 const installer::InstallerState& installer_state,
312 const installer::InstallationState& machine_state,
313 BrowserDistribution::Type type) {
314 DCHECK(SupportsSingleInstall(type) || installer_state.is_multi_install());
315
316 const ProductState* product_state =
317 machine_state.GetProductState(installer_state.system_install(), type);
318
319 // Determine if the product is present prior to the current operation.
320 bool is_present = (product_state != NULL);
321 bool is_uninstall = installer_state.operation() == InstallerState::UNINSTALL;
322
323 // Determine if current operation affects the product.
324 const Product* product = installer_state.FindProduct(type);
325 bool is_affected = (product != NULL);
326
327 // Decide among {(1),(2),(3),(4)}.
328 return is_affected ? !is_uninstall : is_present;
329 }
330
331 bool AdjustProcessPriority() { 456 bool AdjustProcessPriority() {
332 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 457 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
333 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); 458 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess());
334 if (priority_class == 0) { 459 if (priority_class == 0) {
335 PLOG(WARNING) << "Failed to get the process's priority class."; 460 PLOG(WARNING) << "Failed to get the process's priority class.";
336 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || 461 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS ||
337 priority_class == IDLE_PRIORITY_CLASS) { 462 priority_class == IDLE_PRIORITY_CLASS) {
338 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), 463 BOOL result = ::SetPriorityClass(::GetCurrentProcess(),
339 PROCESS_MODE_BACKGROUND_BEGIN); 464 PROCESS_MODE_BACKGROUND_BEGIN);
340 PLOG_IF(WARNING, !result) << "Failed to enter background mode."; 465 PLOG_IF(WARNING, !result) << "Failed to enter background mode.";
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 base::string16 reg_path(kEventLogProvidersRegPath); 850 base::string16 reg_path(kEventLogProvidersRegPath);
726 reg_path.append(InstallFullName()); 851 reg_path.append(InstallFullName());
727 852
728 // TODO(http://crbug.com/668120): If the Event Viewer is open the provider dll 853 // TODO(http://crbug.com/668120): If the Event Viewer is open the provider dll
729 // will fail to get deleted. This doesn't fail the uninstallation altogether 854 // will fail to get deleted. This doesn't fail the uninstallation altogether
730 // but leaves files behind. 855 // but leaves files behind.
731 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, 856 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path,
732 WorkItem::kWow64Default); 857 WorkItem::kWow64Default);
733 } 858 }
734 859
860 void DoLegacyCleanups(const InstallerState& installer_state,
861 InstallStatus install_status) {
862 // Do no harm if the install didn't succeed.
863 if (InstallUtil::GetInstallReturnCode(install_status))
864 return;
865
866 // The cleanups below only apply to normal Chrome, not side-by-side (canary).
867 if (InstallUtil::IsChromeSxSProcess())
868 return;
869
870 RemoveBinariesVersionKey(installer_state);
871 RemoveMultiChromeFrame(installer_state);
872 RemoveAppLauncherVersionKey(installer_state);
873 RemoveAppHostExe(installer_state);
874 RemoveLegacyChromeAppCommands(installer_state);
875 }
876
735 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) 877 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name)
736 : is_enabled_(false) { 878 : is_enabled_(false) {
737 HANDLE temp_handle; 879 HANDLE temp_handle;
738 if (!::OpenProcessToken(::GetCurrentProcess(), 880 if (!::OpenProcessToken(::GetCurrentProcess(),
739 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 881 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
740 &temp_handle)) { 882 &temp_handle)) {
741 return; 883 return;
742 } 884 }
743 token_.Set(temp_handle); 885 token_.Set(temp_handle);
744 886
(...skipping 22 matching lines...) Expand all
767 } 909 }
768 910
769 ScopedTokenPrivilege::~ScopedTokenPrivilege() { 911 ScopedTokenPrivilege::~ScopedTokenPrivilege() {
770 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { 912 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) {
771 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, 913 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_,
772 sizeof(TOKEN_PRIVILEGES), NULL, NULL); 914 sizeof(TOKEN_PRIVILEGES), NULL, NULL);
773 } 915 }
774 } 916 }
775 917
776 } // namespace installer 918 } // namespace installer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698