OLD | NEW |
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 Loading... |
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 Loading... |
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( |
| 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 Frame\". |
| 164 // Multi-install GCF would have had "\Chrome\", and anything else is garbage. |
| 165 |
| 166 UpdatingAppRegistrationData gcf_data( |
| 167 L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}"); |
| 168 base::win::RegKey clients_key; |
| 169 base::win::RegKey client_state_key; |
| 170 |
| 171 const bool has_clients_key = |
| 172 clients_key.Open(installer_state.root_key(), |
| 173 gcf_data.GetVersionKey().c_str(), |
| 174 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS; |
| 175 const bool has_client_state_key = |
| 176 client_state_key.Open(installer_state.root_key(), |
| 177 gcf_data.GetStateKey().c_str(), |
| 178 KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS; |
| 179 if (!has_clients_key && !has_client_state_key) |
| 180 return; // Nothing to check or to clean. |
| 181 |
| 182 base::string16 value; |
| 183 if (has_clients_key && has_client_state_key && |
| 184 clients_key.ReadValue(google_update::kRegVersionField, &value) == |
| 185 ERROR_SUCCESS && |
| 186 !value.empty() && |
| 187 client_state_key.ReadValue(kUninstallStringField, &value) == |
| 188 ERROR_SUCCESS && |
| 189 value.find(L"\\Chrome Frame\\") != base::string16::npos) { |
| 190 return; // Single-install Chrome Frame found. |
| 191 } |
| 192 client_state_key.Close(); |
| 193 clients_key.Close(); |
| 194 |
| 195 // Remnants of multi-install GCF or of a malformed GCF are present. Remove the |
| 196 // Clients and ClientState keys so that Google Update ceases to check for |
| 197 // updates, and the Programs and Features control panel entry to reduce user |
| 198 // confusion. |
| 199 constexpr int kOperations = 3; |
| 200 int success_count = 0; |
| 201 |
| 202 if (InstallUtil::DeleteRegistryKey(installer_state.root_key(), |
| 203 gcf_data.GetVersionKey(), |
| 204 KEY_WOW64_32KEY)) { |
| 205 ++success_count; |
| 206 } |
| 207 if (InstallUtil::DeleteRegistryKey(installer_state.root_key(), |
| 208 gcf_data.GetStateKey(), KEY_WOW64_32KEY)) { |
| 209 ++success_count; |
| 210 } |
| 211 if (InstallUtil::DeleteRegistryKey( |
| 212 installer_state.root_key(), |
| 213 L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" |
| 214 L"Google Chrome Frame", |
| 215 KEY_WOW64_32KEY)) { |
| 216 ++success_count; |
| 217 } |
| 218 DCHECK_LE(success_count, kOperations); |
| 219 |
| 220 // Used for a histogram; do not reorder. |
| 221 enum MultiChromeFrameRemovalResult { |
| 222 ALL_FAILED = 0, |
| 223 PARTIAL_SUCCESS = 1, |
| 224 SUCCESS = 2, |
| 225 NUM_RESULTS |
| 226 }; |
| 227 MultiChromeFrameRemovalResult result = |
| 228 (success_count == kOperations ? SUCCESS : (success_count ? PARTIAL_SUCCESS |
| 229 : ALL_FAILED)); |
| 230 UMA_HISTOGRAM_ENUMERATION("Setup.Install.MultiChromeFrameRemoved", result, |
| 231 NUM_RESULTS); |
| 232 #endif // GOOGLE_CHROME_BUILD |
| 233 } |
| 234 |
| 235 void RemoveAppLauncherVersionKey(const InstallerState& installer_state) { |
| 236 // The app launcher was only registered for Google Chrome. |
| 237 #if defined(GOOGLE_CHROME_BUILD) |
| 238 UpdatingAppRegistrationData reg_data( |
| 239 L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"); |
| 240 |
| 241 base::string16 path(reg_data.GetVersionKey()); |
| 242 if (base::win::RegKey(installer_state.root_key(), path.c_str(), |
| 243 KEY_QUERY_VALUE | KEY_WOW64_32KEY) |
| 244 .Valid()) { |
| 245 const bool succeeded = InstallUtil::DeleteRegistryKey( |
| 246 installer_state.root_key(), path, KEY_WOW64_32KEY); |
| 247 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteAppLauncherClientsKey", |
| 248 succeeded); |
| 249 } |
| 250 #endif // GOOGLE_CHROME_BUILD |
| 251 } |
| 252 |
| 253 void RemoveAppHostExe(const InstallerState& installer_state) { |
| 254 // The app host was only installed for Google Chrome. |
| 255 #if defined(GOOGLE_CHROME_BUILD) |
| 256 base::FilePath app_host( |
| 257 installer_state.target_path().Append(FILE_PATH_LITERAL("app_host.exe"))); |
| 258 |
| 259 if (base::PathExists(app_host)) { |
| 260 const bool succeeded = base::DeleteFile(app_host, false); |
| 261 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteAppHost", succeeded); |
| 262 } |
| 263 #endif // GOOGLE_CHROME_BUILD |
| 264 } |
| 265 |
| 266 void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) { |
| 267 // These app commands were only registered for Google Chrome. |
| 268 #if defined(GOOGLE_CHROME_BUILD) |
| 269 base::string16 path(GetRegistrationDataCommandKey( |
| 270 installer_state.product().distribution()->GetAppRegistrationData(), |
| 271 L"install-extension")); |
| 272 |
| 273 if (base::win::RegKey(installer_state.root_key(), path.c_str(), |
| 274 KEY_QUERY_VALUE | KEY_WOW64_32KEY) |
| 275 .Valid()) { |
| 276 const bool succeeded = InstallUtil::DeleteRegistryKey( |
| 277 installer_state.root_key(), path, KEY_WOW64_32KEY); |
| 278 UMA_HISTOGRAM_BOOLEAN("Setup.Install.DeleteInstallExtensionCommand", |
| 279 succeeded); |
| 280 } |
| 281 #endif // GOOGLE_CHROME_BUILD |
| 282 } |
| 283 |
135 } // namespace | 284 } // namespace |
136 | 285 |
137 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; | 286 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; |
138 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS"; | 287 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS"; |
139 | 288 |
140 int CourgettePatchFiles(const base::FilePath& src, | 289 int CourgettePatchFiles(const base::FilePath& src, |
141 const base::FilePath& patch, | 290 const base::FilePath& patch, |
142 const base::FilePath& dest) { | 291 const base::FilePath& dest) { |
143 VLOG(1) << "Applying Courgette patch " << patch.value() | 292 VLOG(1) << "Applying Courgette patch " << patch.value() |
144 << " to file " << src.value() | 293 << " to file " << src.value() |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 PLOG(ERROR) << "VirtualAllocEx"; | 444 PLOG(ERROR) << "VirtualAllocEx"; |
296 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0)); | 445 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0)); |
297 } | 446 } |
298 ::CloseHandle(pi.hThread); | 447 ::CloseHandle(pi.hThread); |
299 ::CloseHandle(pi.hProcess); | 448 ::CloseHandle(pi.hProcess); |
300 } | 449 } |
301 | 450 |
302 return ok != FALSE; | 451 return ok != FALSE; |
303 } | 452 } |
304 | 453 |
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() { | 454 bool AdjustProcessPriority() { |
332 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 455 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
333 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); | 456 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); |
334 if (priority_class == 0) { | 457 if (priority_class == 0) { |
335 PLOG(WARNING) << "Failed to get the process's priority class."; | 458 PLOG(WARNING) << "Failed to get the process's priority class."; |
336 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || | 459 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || |
337 priority_class == IDLE_PRIORITY_CLASS) { | 460 priority_class == IDLE_PRIORITY_CLASS) { |
338 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), | 461 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), |
339 PROCESS_MODE_BACKGROUND_BEGIN); | 462 PROCESS_MODE_BACKGROUND_BEGIN); |
340 PLOG_IF(WARNING, !result) << "Failed to enter background mode."; | 463 PLOG_IF(WARNING, !result) << "Failed to enter background mode."; |
(...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 base::string16 reg_path(kEventLogProvidersRegPath); | 848 base::string16 reg_path(kEventLogProvidersRegPath); |
726 reg_path.append(InstallFullName()); | 849 reg_path.append(InstallFullName()); |
727 | 850 |
728 // TODO(http://crbug.com/668120): If the Event Viewer is open the provider dll | 851 // 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 | 852 // will fail to get deleted. This doesn't fail the uninstallation altogether |
730 // but leaves files behind. | 853 // but leaves files behind. |
731 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, | 854 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, |
732 WorkItem::kWow64Default); | 855 WorkItem::kWow64Default); |
733 } | 856 } |
734 | 857 |
| 858 void DoLegacyCleanups(const InstallerState& installer_state, |
| 859 InstallStatus install_status) { |
| 860 // Do no harm if the install didn't succeed. |
| 861 if (InstallUtil::GetInstallReturnCode(install_status)) |
| 862 return; |
| 863 |
| 864 // The cleanups below only apply to normal Chrome, not side-by-side (canary). |
| 865 if (InstallUtil::IsChromeSxSProcess()) |
| 866 return; |
| 867 |
| 868 RemoveBinariesVersionKey(installer_state); |
| 869 RemoveMultiChromeFrame(installer_state); |
| 870 RemoveAppLauncherVersionKey(installer_state); |
| 871 RemoveAppHostExe(installer_state); |
| 872 RemoveLegacyChromeAppCommands(installer_state); |
| 873 } |
| 874 |
735 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) | 875 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) |
736 : is_enabled_(false) { | 876 : is_enabled_(false) { |
737 HANDLE temp_handle; | 877 HANDLE temp_handle; |
738 if (!::OpenProcessToken(::GetCurrentProcess(), | 878 if (!::OpenProcessToken(::GetCurrentProcess(), |
739 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, | 879 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
740 &temp_handle)) { | 880 &temp_handle)) { |
741 return; | 881 return; |
742 } | 882 } |
743 token_.Set(temp_handle); | 883 token_.Set(temp_handle); |
744 | 884 |
(...skipping 22 matching lines...) Expand all Loading... |
767 } | 907 } |
768 | 908 |
769 ScopedTokenPrivilege::~ScopedTokenPrivilege() { | 909 ScopedTokenPrivilege::~ScopedTokenPrivilege() { |
770 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { | 910 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { |
771 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, | 911 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, |
772 sizeof(TOKEN_PRIVILEGES), NULL, NULL); | 912 sizeof(TOKEN_PRIVILEGES), NULL, NULL); |
773 } | 913 } |
774 } | 914 } |
775 | 915 |
776 } // namespace installer | 916 } // namespace installer |
OLD | NEW |