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()); | |
gab
2017/01/05 22:08:01
Why was this called the "version key" again? That
grt (UTC plus 2)
2017/01/06 10:25:53
Historical accident, I think. It's been that way f
| |
143 if (base::win::RegKey(installer_state.root_key(), path.c_str(), | |
144 KEY_QUERY_VALUE | KEY_WOW64_32KEY) | |
145 .Valid() && | |
146 InstallUtil::DeleteRegistryKey(installer_state.root_key(), path, | |
147 KEY_WOW64_32KEY)) { | |
148 UMA_HISTOGRAM_BOOLEAN("Setup.Install.BinariesRemoved", true); | |
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 | |
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) { | |
gab
2016/12/22 19:05:10
Single Chrome Frame still exists? Frozen to some o
grt (UTC plus 2)
2017/01/02 10:45:03
Yes, and still has active users!
gab
2017/01/05 22:08:01
Ok but which code is this moving? I can't seem to
grt (UTC plus 2)
2017/01/06 10:25:53
UninstallMultiChromeFrameIfPresent in setup_main.c
| |
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(); | |
199 clients_key.Close(); | |
200 | |
201 InstallUtil::DeleteRegistryKey(installer_state.root_key(), | |
202 gcf_data.GetVersionKey(), KEY_WOW64_32KEY); | |
203 InstallUtil::DeleteRegistryKey(installer_state.root_key(), | |
204 gcf_data.GetStateKey(), KEY_WOW64_32KEY); | |
205 InstallUtil::DeleteRegistryKey( | |
206 installer_state.root_key(), | |
207 L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" | |
208 L"Google Chrome Frame", | |
209 KEY_WOW64_32KEY); | |
210 | |
211 UMA_HISTOGRAM_BOOLEAN("Setup.Install.MultiChromeFrameRemoved", true); | |
212 #endif | |
213 } | |
214 | |
215 void RemoveAppLauncherVersionKey(const InstallerState& installer_state) { | |
216 // The app launcher was only registered for Google Chrome. | |
217 #if defined(GOOGLE_CHROME_BUILD) | |
218 UpdatingAppRegistrationData reg_data( | |
219 L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"); | |
220 | |
221 base::string16 path(reg_data.GetVersionKey()); | |
222 if (base::win::RegKey(installer_state.root_key(), path.c_str(), | |
223 KEY_QUERY_VALUE | KEY_WOW64_32KEY) | |
224 .Valid() && | |
225 InstallUtil::DeleteRegistryKey(installer_state.root_key(), path, | |
gab
2016/12/22 19:05:10
I'm not 100% sure about the destruction order here
grt (UTC plus 2)
2017/01/02 10:45:03
"If the second expression is evaluated, every valu
gab
2017/01/05 22:08:01
Cool beans :)
| |
226 KEY_WOW64_32KEY)) { | |
227 UMA_HISTOGRAM_BOOLEAN("Setup.Install.AppLauncherRemoved", true); | |
228 } | |
229 #endif // GOOGLE_CHROME_BUILD | |
230 } | |
231 | |
232 void RemoveAppHostExe(const InstallerState& installer_state) { | |
233 // The app host was only installed for Google Chrome. | |
234 #if defined(GOOGLE_CHROME_BUILD) | |
235 base::FilePath app_host( | |
236 installer_state.target_path().Append(FILE_PATH_LITERAL("app_host.exe"))); | |
237 | |
238 if (base::PathExists(app_host) && base::DeleteFile(app_host, false)) | |
239 UMA_HISTOGRAM_BOOLEAN("Setup.Install.AppHostRemoved", true); | |
240 #endif | |
241 } | |
242 | |
243 void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) { | |
244 // These app commands were only registered for Google Chrome. | |
245 #if defined(GOOGLE_CHROME_BUILD) | |
246 base::string16 path(GetRegistrationDataCommandKey( | |
247 installer_state.product().distribution()->GetAppRegistrationData(), | |
248 L"install-extension")); | |
249 | |
250 if (base::win::RegKey(installer_state.root_key(), path.c_str(), | |
251 KEY_QUERY_VALUE | KEY_WOW64_32KEY) | |
252 .Valid() && | |
253 InstallUtil::DeleteRegistryKey(installer_state.root_key(), path, | |
254 KEY_WOW64_32KEY)) { | |
255 UMA_HISTOGRAM_BOOLEAN("Setup.Install.InstallExtensionCommandRemoved", true); | |
gab
2016/12/22 19:05:10
Is UMA live until the very end of setup.exe? (DoLe
grt (UTC plus 2)
2017/01/02 10:45:03
It's alive until the end of wWinMain (torn down in
| |
256 } | |
257 #endif | |
258 } | |
259 | |
135 } // namespace | 260 } // namespace |
136 | 261 |
137 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; | 262 const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; |
138 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS"; | 263 const char kUnPackNTSTATUSMetricsName[] = "Setup.Install.LzmaUnPackNTSTATUS"; |
139 | 264 |
140 int CourgettePatchFiles(const base::FilePath& src, | 265 int CourgettePatchFiles(const base::FilePath& src, |
141 const base::FilePath& patch, | 266 const base::FilePath& patch, |
142 const base::FilePath& dest) { | 267 const base::FilePath& dest) { |
143 VLOG(1) << "Applying Courgette patch " << patch.value() | 268 VLOG(1) << "Applying Courgette patch " << patch.value() |
144 << " to file " << src.value() | 269 << " to file " << src.value() |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
295 PLOG(ERROR) << "VirtualAllocEx"; | 420 PLOG(ERROR) << "VirtualAllocEx"; |
296 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0)); | 421 ::TerminateProcess(pi.hProcess, ~static_cast<UINT>(0)); |
297 } | 422 } |
298 ::CloseHandle(pi.hThread); | 423 ::CloseHandle(pi.hThread); |
299 ::CloseHandle(pi.hProcess); | 424 ::CloseHandle(pi.hProcess); |
300 } | 425 } |
301 | 426 |
302 return ok != FALSE; | 427 return ok != FALSE; |
303 } | 428 } |
304 | 429 |
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() { | 430 bool AdjustProcessPriority() { |
332 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { | 431 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { |
333 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); | 432 DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); |
334 if (priority_class == 0) { | 433 if (priority_class == 0) { |
335 PLOG(WARNING) << "Failed to get the process's priority class."; | 434 PLOG(WARNING) << "Failed to get the process's priority class."; |
336 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || | 435 } else if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || |
337 priority_class == IDLE_PRIORITY_CLASS) { | 436 priority_class == IDLE_PRIORITY_CLASS) { |
338 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), | 437 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), |
339 PROCESS_MODE_BACKGROUND_BEGIN); | 438 PROCESS_MODE_BACKGROUND_BEGIN); |
340 PLOG_IF(WARNING, !result) << "Failed to enter background mode."; | 439 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); | 824 base::string16 reg_path(kEventLogProvidersRegPath); |
726 reg_path.append(InstallFullName()); | 825 reg_path.append(InstallFullName()); |
727 | 826 |
728 // TODO(http://crbug.com/668120): If the Event Viewer is open the provider dll | 827 // 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 | 828 // will fail to get deleted. This doesn't fail the uninstallation altogether |
730 // but leaves files behind. | 829 // but leaves files behind. |
731 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, | 830 InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, |
732 WorkItem::kWow64Default); | 831 WorkItem::kWow64Default); |
733 } | 832 } |
734 | 833 |
834 void DoLegacyCleanups(const InstallerState& installer_state, | |
835 InstallStatus install_status) { | |
836 // Do no harm if the install didn't succeed. | |
837 if (InstallUtil::GetInstallReturnCode(install_status)) | |
838 return; | |
839 | |
840 // The cleanups below only apply to normal Chrome, not side-by-side (canary). | |
841 if (InstallUtil::IsChromeSxSProcess()) | |
842 return; | |
843 | |
844 RemoveBinariesVersionKey(installer_state); | |
845 RemoveMultiChromeFrame(installer_state); | |
846 RemoveAppLauncherVersionKey(installer_state); | |
847 RemoveAppHostExe(installer_state); | |
848 RemoveLegacyChromeAppCommands(installer_state); | |
849 } | |
850 | |
735 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) | 851 ScopedTokenPrivilege::ScopedTokenPrivilege(const wchar_t* privilege_name) |
736 : is_enabled_(false) { | 852 : is_enabled_(false) { |
737 HANDLE temp_handle; | 853 HANDLE temp_handle; |
738 if (!::OpenProcessToken(::GetCurrentProcess(), | 854 if (!::OpenProcessToken(::GetCurrentProcess(), |
739 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, | 855 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, |
740 &temp_handle)) { | 856 &temp_handle)) { |
741 return; | 857 return; |
742 } | 858 } |
743 token_.Set(temp_handle); | 859 token_.Set(temp_handle); |
744 | 860 |
(...skipping 22 matching lines...) Expand all Loading... | |
767 } | 883 } |
768 | 884 |
769 ScopedTokenPrivilege::~ScopedTokenPrivilege() { | 885 ScopedTokenPrivilege::~ScopedTokenPrivilege() { |
770 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { | 886 if (is_enabled_ && previous_privileges_.PrivilegeCount != 0) { |
771 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, | 887 ::AdjustTokenPrivileges(token_.Get(), FALSE, &previous_privileges_, |
772 sizeof(TOKEN_PRIVILEGES), NULL, NULL); | 888 sizeof(TOKEN_PRIVILEGES), NULL, NULL); |
773 } | 889 } |
774 } | 890 } |
775 | 891 |
776 } // namespace installer | 892 } // namespace installer |
OLD | NEW |