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( | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |