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

Side by Side Diff: setup/setup_google_update.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 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
« no previous file with comments | « setup/setup_google_update.h ('k') | setup/setup_google_update_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2007-2010 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 // ========================================================================
15
16 #include "omaha/setup/setup_google_update.h"
17
18 #include <msi.h>
19 #include <atlpath.h>
20 #include <vector>
21 #include "base/basictypes.h"
22 #include "omaha/base/app_util.h"
23 #include "omaha/base/atlregmapex.h"
24 #include "omaha/base/const_object_names.h"
25 #include "omaha/base/const_utils.h"
26 #include "omaha/base/constants.h"
27 #include "omaha/base/debug.h"
28 #include "omaha/base/error.h"
29 #include "omaha/base/file.h"
30 #include "omaha/base/highres_timer-win32.h"
31 #include "omaha/base/logging.h"
32 #include "omaha/base/omaha_version.h"
33 #include "omaha/base/path.h"
34 #include "omaha/base/reg_key.h"
35 #include "omaha/base/scoped_any.h"
36 #include "omaha/base/service_utils.h"
37 #include "omaha/base/utils.h"
38 #include "omaha/base/user_info.h"
39 #include "omaha/common/command_line_builder.h"
40 #include "omaha/common/config_manager.h"
41 #include "omaha/common/const_cmd_line.h"
42 #include "omaha/common/const_goopdate.h"
43 #include "omaha/common/goopdate_utils.h"
44 #include "omaha/common/scheduled_task_utils.h"
45 #include "omaha/setup/setup_metrics.h"
46 #include "omaha/setup/setup_service.h"
47
48 namespace omaha {
49
50 namespace {
51
52 #ifdef _DEBUG
53 HRESULT VerifyCOMLocalServerRegistration(bool is_machine) {
54 // TODO(omaha3): Implement this for Omaha 3. Specifically, this code assumes
55 // Setup is running from the installed location, which is no longer true.
56 #if 0
57 // Validate the following:
58 // * LocalServer32 under CLSID_OnDemandMachineAppsClass or
59 // CLSID_OnDemandUserAppsClass should be ...Google\Update\GoogleUpdate.exe.
60 // * InProcServer32 under CLSID of IID_IGoogleUpdate should be
61 // ...Google\Update\{version}\goopdate.dll.
62 // * ProxyStubClsid32 under IGoogleUpdate interface should be the CLSID of the
63 // proxy, which is IID_IGoogleUpdate.
64
65 CString base_clsid_key(goopdate_utils::GetHKRoot());
66 base_clsid_key += _T("\\Software\\Classes\\CLSID\\");
67 CString ondemand_clsid_key(base_clsid_key);
68 ondemand_clsid_key += GuidToString(is_machine ?
69 __uuidof(OnDemandMachineAppsClass) :
70 __uuidof(OnDemandUserAppsClass));
71 CString local_server_key(ondemand_clsid_key + _T("\\LocalServer32"));
72 CString installed_server;
73 ASSERT1(SUCCEEDED(RegKey::GetValue(local_server_key,
74 NULL,
75 &installed_server)));
76 ASSERT1(!installed_server.IsEmpty());
77
78 CString expected_server(app_util::GetModulePath(NULL));
79 EnclosePath(&expected_server);
80 ASSERT1(!expected_server.IsEmpty());
81 SETUP_LOG(L3, (_T("[installed_server=%s][expected_server=%s]"),
82 installed_server, expected_server));
83 ASSERT1(installed_server == expected_server);
84
85 const GUID proxy_clsid = PROXY_CLSID_IS;
86 CString ondemand_proxy_clsid_key(base_clsid_key);
87 ondemand_proxy_clsid_key += GuidToString(proxy_clsid);
88 CString inproc_server_key(ondemand_proxy_clsid_key + _T("\\InProcServer32"));
89 ASSERT1(SUCCEEDED(RegKey::GetValue(inproc_server_key,
90 NULL,
91 &installed_server)));
92 ASSERT1(!installed_server.IsEmpty());
93 expected_server = app_util::GetCurrentModulePath();
94 ASSERT1(!expected_server.IsEmpty());
95 SETUP_LOG(L3, (_T("[installed proxy=%s][expected proxy=%s]"),
96 installed_server, expected_server));
97 ASSERT1(installed_server == expected_server);
98
99 CString igoogleupdate_interface_key(goopdate_utils::GetHKRoot());
100 igoogleupdate_interface_key += _T("\\Software\\Classes\\Interface\\");
101 igoogleupdate_interface_key += GuidToString(__uuidof(IGoogleUpdate));
102 igoogleupdate_interface_key += _T("\\ProxyStubClsid32");
103 CString proxy_interface_value;
104 ASSERT1(SUCCEEDED(RegKey::GetValue(igoogleupdate_interface_key,
105 NULL,
106 &proxy_interface_value)));
107 ASSERT1(!proxy_interface_value.IsEmpty());
108 ASSERT1(proxy_interface_value == GuidToString(proxy_clsid));
109 #else
110 UNREFERENCED_PARAMETER(is_machine);
111 #endif
112 return S_OK;
113 }
114 #endif
115
116 HRESULT RegisterOrUnregisterService(bool reg, CString service_path) {
117 EnclosePath(&service_path);
118
119 CommandLineBuilder builder(reg ? COMMANDLINE_MODE_SERVICE_REGISTER :
120 COMMANDLINE_MODE_SERVICE_UNREGISTER);
121 CString cmd_line = builder.GetCommandLineArgs();
122 return RegisterOrUnregisterExe(service_path, cmd_line);
123 }
124
125 } // namespace
126
127 SetupGoogleUpdate::SetupGoogleUpdate(bool is_machine)
128 : is_machine_(is_machine),
129 extra_code1_(S_OK)
130 #ifdef _DEBUG
131 , have_called_uninstall_previous_versions_(false)
132 #endif
133 { // NOLINT
134 this_version_ = GetVersionString();
135 }
136
137 SetupGoogleUpdate::~SetupGoogleUpdate() {
138 SETUP_LOG(L2, (_T("[SetupGoogleUpdate::~SetupGoogleUpdate]")));
139 }
140
141 // TODO(omaha): Add a VerifyInstall() method that can be called by /handoff
142 // instances to verify the installation and call FinishInstall() if it fails.
143
144 // Assumes the caller is ensuring this is the only running instance of setup.
145 // The original process holds the lock while it waits for this one to complete.
146 HRESULT SetupGoogleUpdate::FinishInstall() {
147 SETUP_LOG(L2, (_T("[SetupGoogleUpdate::FinishInstall]")));
148
149 HRESULT hr = InstallRegistryValues();
150 if (FAILED(hr)) {
151 SETUP_LOG(LE, (_T("[InstallRegistryValues failed][0x%08x]"), hr));
152 if (E_ACCESSDENIED == hr) {
153 return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS;
154 }
155 return hr;
156 }
157
158 hr = InstallLaunchMechanisms();
159 if (FAILED(hr)) {
160 SETUP_LOG(LE, (_T("[InstallLaunchMechanisms failed][0x%08x]"), hr));
161 return hr;
162 }
163
164 hr = InstallMsiHelper();
165 if (FAILED(hr)) {
166 SETUP_LOG(L1, (_T("[InstallMsiHelper failed][0x%08x]"), hr));
167 // TODO(omaha): Retry on ERROR_INSTALL_ALREADY_RUNNING like InstallerWrapper
168 // if we move helper MSI installation after app installation.
169 ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr ||
170 HRESULT_FROM_WIN32(ERROR_INSTALL_ALREADY_RUNNING) == hr);
171 }
172
173 hr = RegisterOrUnregisterCOMLocalServer(true);
174 if (FAILED(hr)) {
175 OPT_LOG(LW, (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%x]"), hr));
176
177 // Fall through. Omaha will attempt to install using the in-proc mode.
178 }
179
180 ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));
181
182 // We would prefer to uninstall previous versions last, but the web plugin
183 // requires that the old plugin is uninstalled before installing the new one.
184 VERIFY1(SUCCEEDED(UninstallPreviousVersions()));
185
186 // Writing this value indicates that this Omaha version was successfully
187 // installed. This is an artifact of Omaha 2 when pv was set earlier in Setup.
188 CString reg_update = ConfigManager::Instance()->registry_update(is_machine_);
189 hr = RegKey::SetValue(reg_update, kRegValueInstalledVersion, this_version_);
190 if (FAILED(hr)) {
191 return hr;
192 }
193
194 // Delete the "LastChecked" registry value after a successful install or
195 // update so that Omaha checks for updates soon after the install. This
196 // helps detecting a heart beat from the new version sooner as well as
197 // avoiding deferring application updates for too long in the case where both
198 // Omaha and application updates are available.
199 RegKey::DeleteValue(reg_update, kRegValueLastChecked);
200
201 return S_OK;
202 }
203
204 // Version values are written at the end of setup, not here.
205 HRESULT SetupGoogleUpdate::InstallRegistryValues() {
206 OPT_LOG(L3, (_T("[SetupGoogleUpdate::InstallRegistryValues]")));
207
208 const ConfigManager* cm = ConfigManager::Instance();
209 const TCHAR* keys[] = { cm->registry_google(is_machine_),
210 cm->registry_update(is_machine_),
211 cm->registry_client_state(is_machine_),
212 cm->registry_clients(is_machine_),
213 cm->registry_clients_goopdate(is_machine_),
214 cm->registry_client_state_goopdate(is_machine_),
215 };
216
217 HRESULT hr = RegKey::CreateKeys(keys, arraysize(keys));
218 if (FAILED(hr)) {
219 OPT_LOG(LE, (_T("[Failed to create reg keys][0x%08x]"), hr));
220 return hr;
221 }
222
223 if (is_machine_) {
224 hr = CreateClientStateMedium();
225 if (FAILED(hr)) {
226 SETUP_LOG(L3, (_T("[CreateClientStateMedium failed][0x%08x]"), hr));
227 return hr;
228 }
229 }
230
231 CString shell_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
232 if (shell_path.IsEmpty() || !File::Exists(shell_path)) {
233 SETUP_LOG(LE, (_T("[Failed to get valid shell path]")));
234 return E_FAIL;
235 }
236 hr = RegKey::SetValue(cm->registry_update(is_machine_),
237 kRegValueInstalledPath,
238 shell_path);
239 if (FAILED(hr)) {
240 SETUP_LOG(LE, (_T("[Failed to write shell path][0x%08x]"), hr));
241 return hr;
242 }
243
244 ASSERT1(!this_version_.IsEmpty());
245
246 const CString omaha_clients_key_path =
247 cm->registry_clients_goopdate(is_machine_);
248
249 // Set the version so the constant shell will know which version to use.
250 // TODO(omaha3): This should be the atomic switch of the version, but it must
251 // be called before registering the COM servers because GoogleUpdate.exe needs
252 // the pv to find goopdate.dll. We may need to support rolling this back.
253 hr = RegKey::SetValue(omaha_clients_key_path,
254 kRegValueProductVersion,
255 this_version_);
256 if (FAILED(hr)) {
257 SETUP_LOG(LE, (_T("[Failed to set version in registry][0x%08x]"), hr));
258 if (E_ACCESSDENIED == hr) {
259 return GOOPDATE_E_ACCESSDENIED_SETUP_REG_ACCESS;
260 }
261 return hr;
262 }
263
264 // Write Omaha's localized name to the registry. During installation, this
265 // will use the installation language. For self-updates, it will use the
266 // user's/Local System's language.
267 CString omaha_name;
268 if (!omaha_name.LoadString(IDS_PRODUCT_DISPLAY_NAME)) {
269 ASSERT1(false);
270 omaha_name = kAppName;
271 }
272 VERIFY1(SUCCEEDED(RegKey::SetValue(omaha_clients_key_path,
273 kRegValueAppName,
274 omaha_name)));
275
276 // Set pv in ClientState for consistency. Optional, so ignore errors.
277 const CString omaha_client_state_key_path =
278 cm->registry_client_state_goopdate(is_machine_);
279 VERIFY1(SUCCEEDED(RegKey::SetValue(omaha_client_state_key_path,
280 kRegValueProductVersion,
281 this_version_)));
282
283 if (is_machine_) {
284 VERIFY1(SUCCEEDED(goopdate_utils::EnableSEHOP(true)));
285 }
286
287 return S_OK;
288 }
289
290 // Creates the ClientStateMedium key and adds ACLs that allows authenticated
291 // users to read and write values in its subkeys.
292 // Since this key is not as secure as other keys, the supported values must be
293 // limited and the use of them must be carefully designed.
294 HRESULT SetupGoogleUpdate::CreateClientStateMedium() {
295 ASSERT1(is_machine_);
296
297 // Authenticated non-admins may read, write, and create values.
298 const ACCESS_MASK kNonAdminAccessMask = KEY_READ | KEY_SET_VALUE;
299 // The override privileges apply to all subkeys and values but not to the
300 // ClientStateMedium key itself.
301 const uint8 kAceFlags =
302 CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
303
304 const CString key_full_name =
305 ConfigManager::Instance()->machine_registry_client_state_medium();
306 HRESULT hr = RegKey::CreateKey(key_full_name);
307 if (FAILED(hr)) {
308 SETUP_LOG(LE, (_T("[Create ClientStateMedium failed][0x%08x]"), hr));
309 return hr;
310 }
311
312 // GetNamedSecurityInfo requires the key name start with "MACHINE".
313 // TODO(omaha): Replace AddAllowedAce or add an override that takes a handle
314 // instead of a name to eliminate this issue.
315 CString compatible_key_name = key_full_name;
316 VERIFY1(1 == compatible_key_name.Replace(MACHINE_KEY_NAME, _T("MACHINE")));
317
318 hr = AddAllowedAce(compatible_key_name,
319 SE_REGISTRY_KEY,
320 Sids::Interactive(),
321 kNonAdminAccessMask,
322 kAceFlags);
323 if (FAILED(hr)) {
324 SETUP_LOG(LE, (_T("[AddAllowedAce failed][%s][0x%08x]"),
325 key_full_name, hr));
326 return hr;
327 }
328
329 return S_OK;
330 }
331
332 HRESULT SetupGoogleUpdate::InstallLaunchMechanisms() {
333 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallLaunchMechanisms]")));
334 if (is_machine_) {
335 HRESULT hr = InstallMachineLaunchMechanisms();
336 if (FAILED(hr)) {
337 SETUP_LOG(LE, (_T("[InstallMachineLaunchMechanisms fail][0x%08x]"), hr));
338 return hr;
339 }
340 } else {
341 HRESULT hr = InstallUserLaunchMechanisms();
342 if (FAILED(hr)) {
343 SETUP_LOG(LE, (_T("[InstallUserLaunchMechanisms failed][0x%08x]"), hr));
344 return hr;
345 }
346 }
347
348 return S_OK;
349 }
350
351 void SetupGoogleUpdate::UninstallLaunchMechanisms() {
352 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallLaunchMechanisms]")));
353 if (is_machine_) {
354 CString current_dir = app_util::GetModuleDirectory(NULL);
355 CString service_path = ConcatenatePath(current_dir, kServiceFileName);
356
357 VERIFY1(SUCCEEDED(RegisterOrUnregisterService(false, service_path)));
358 } else {
359 // We only need to do this in case of the user goopdate, as
360 // there is no machine Run at startup installation.
361 VERIFY1(SUCCEEDED(ConfigureUserRunAtStartup(false))); // delete entry
362 }
363
364 VERIFY1(SUCCEEDED(scheduled_task_utils::UninstallGoopdateTasks(is_machine_)));
365 }
366
367 HRESULT SetupGoogleUpdate::InstallScheduledTask() {
368 CString exe_path = goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
369
370 HighresTimer metrics_timer;
371 const ULONGLONG install_task_start_ms = metrics_timer.GetElapsedMs();
372
373 HRESULT hr = scheduled_task_utils::InstallGoopdateTasks(exe_path,
374 is_machine_);
375
376 if (SUCCEEDED(hr)) {
377 const ULONGLONG install_task_end_ms = metrics_timer.GetElapsedMs();
378 ASSERT1(install_task_end_ms >= install_task_start_ms);
379 metric_setup_install_task_ms.AddSample(
380 install_task_end_ms - install_task_start_ms);
381 ++metric_setup_install_task_succeeded;
382 } else {
383 OPT_LOG(LEVEL_ERROR, (_T("[Install task failed][0x%08x]"), hr));
384 metric_setup_install_task_error = hr;
385 }
386
387 return hr;
388 }
389
390 // Assumes the any existing service instance has been stopped
391 // TODO(omaha): Provide service_hr and task_hr failures in a ping.
392 // They are no longer being provided in the URL.
393 HRESULT SetupGoogleUpdate::InstallMachineLaunchMechanisms() {
394 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMachineLaunchMechanisms]")));
395 ++metric_setup_install_service_task_total;
396
397 // Install the service and scheduled task. Failing to install both will
398 // fail setup.
399 OPT_LOG(L1, (_T("[Installing service]")));
400 HighresTimer metrics_timer;
401
402 HRESULT service_hr = RegisterOrUnregisterService(true,
403 goopdate_utils::BuildGoogleUpdateExePath(is_machine_));
404 ASSERT(SUCCEEDED(service_hr), (_T("[registration err][0x%x]"), service_hr));
405
406 if (SUCCEEDED(service_hr)) {
407 metric_setup_install_service_ms.AddSample(
408 metrics_timer.GetElapsedMs());
409 ++metric_setup_install_service_succeeded;
410 } else {
411 metric_setup_install_service_failed_ms.AddSample(
412 metrics_timer.GetElapsedMs());
413 OPT_LOG(LEVEL_ERROR, (_T("[Install service failed][0x%08x]"), service_hr));
414 metric_setup_install_service_error = service_hr;
415 }
416
417 HRESULT task_hr = InstallScheduledTask();
418
419 if (FAILED(service_hr) && FAILED(task_hr)) {
420 ++metric_setup_install_service_and_task_failed;
421 extra_code1_ = task_hr;
422 return service_hr;
423 }
424
425 // TODO(omaha3): Setup does not know about OEM mode. Figure out a
426 // different way to do this. Maybe just verify that both are installed.
427 #if 0
428 if (args_->is_oem_set) {
429 // OEM installs are on clean systems in a controlled environment. We expect
430 // both mechanisms to install.
431 if (FAILED(service_hr)) {
432 return service_hr;
433 }
434 if (FAILED(task_hr)) {
435 return task_hr;
436 }
437 }
438 #endif
439
440 if (SUCCEEDED(service_hr) && SUCCEEDED(task_hr)) {
441 ++metric_setup_install_service_and_task_succeeded;
442 }
443
444 return S_OK;
445 }
446
447 HRESULT SetupGoogleUpdate::InstallUserLaunchMechanisms() {
448 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallUserLaunchMechanisms]")));
449
450 HRESULT run_hr = ConfigureUserRunAtStartup(true); // install
451 ASSERT(SUCCEEDED(run_hr), (_T("ConfigureRunAtStartup 0x%x"), run_hr));
452
453 HRESULT task_hr = InstallScheduledTask();
454 ASSERT(SUCCEEDED(task_hr), (_T("InstallScheduledTask 0x%x"), task_hr));
455
456 if (FAILED(run_hr) && FAILED(task_hr)) {
457 // We need atleast one launch mechanism.
458 extra_code1_ = task_hr;
459 return run_hr;
460 }
461
462 return S_OK;
463 }
464
465 // Sets a value in the Run key in the user registry to start the core.
466 HRESULT SetupGoogleUpdate::ConfigureUserRunAtStartup(bool install) {
467 SETUP_LOG(L3, (_T("SetupGoogleUpdate::ConfigureUserRunAtStartup")));
468 // Always send false argument as this method is only called for user
469 // goopdate installs.
470 CString core_cmd = BuildCoreProcessCommandLine();
471 return ConfigureRunAtStartup(USER_KEY_NAME, kRunValueName, core_cmd, install);
472 }
473
474 HRESULT SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer(bool reg) {
475 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::RegisterOrUnregisterCOMLocalServer]")
476 _T("[%d]"), reg));
477 const CString google_update_path =
478 goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
479 CString register_cmd;
480 register_cmd.Format(_T("/%s"), reg ? kCmdRegServer : kCmdUnregServer);
481 HRESULT hr = RegisterOrUnregisterExe(google_update_path, register_cmd);
482 if (FAILED(hr)) {
483 SETUP_LOG(LE, (_T("[RegisterOrUnregisterExe failed][0x%08x]"), hr));
484 return hr;
485 }
486 return S_OK;
487 }
488
489 // Assumes that the MSI is in the current directory.
490 // To debug MSI failures, use the following statement:
491 // ::MsiEnableLog(INSTALLLOGMODE_VERBOSE, _T("C:\\msi.log"), NULL);
492 HRESULT SetupGoogleUpdate::InstallMsiHelper() {
493 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallMsiHelper]")));
494 if (!is_machine_) {
495 return S_OK;
496 }
497
498 ++metric_setup_helper_msi_install_total;
499 HighresTimer metrics_timer;
500
501 const CPath msi_path(BuildSupportFileInstallPath(kHelperInstallerName));
502 ASSERT1(File::Exists(msi_path));
503
504 // Setting INSTALLUILEVEL_NONE causes installation to be silent and not
505 // create a restore point.
506 ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
507
508 // Try a normal install.
509 UINT res = ::MsiInstallProduct(msi_path, kMsiSuppressAllRebootsCmdLine);
510 if (ERROR_PRODUCT_VERSION == res) {
511 // The product may already be installed. Force a reinstall of everything.
512 SETUP_LOG(L3, (_T("[ERROR_PRODUCT_VERSION returned - forcing reinstall]")));
513 CString force_install_cmd_line;
514 force_install_cmd_line.Format(_T("REINSTALL=ALL REINSTALLMODE=vamus %s"),
515 kMsiSuppressAllRebootsCmdLine);
516 res = ::MsiInstallProduct(msi_path, force_install_cmd_line);
517 }
518
519 HRESULT hr = HRESULT_FROM_WIN32(res);
520 if (FAILED(hr)) {
521 SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));
522 return hr;
523 }
524
525 metric_setup_helper_msi_install_ms.AddSample(metrics_timer.GetElapsedMs());
526 ++metric_setup_helper_msi_install_succeeded;
527 return S_OK;
528 }
529
530 // The MSI is uninstalled.
531 // TODO(omaha): Make sure this works after deleting the MSI.
532 HRESULT SetupGoogleUpdate::UninstallMsiHelper() {
533 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallMsiHelper]")));
534 if (!is_machine_) {
535 return S_OK;
536 }
537
538 // Setting INSTALLUILEVEL_NONE causes installation to be silent and not
539 // create a restore point.
540 ::MsiSetInternalUI(INSTALLUILEVEL_NONE, NULL);
541
542 // MSDN says that eInstallState must be INSTALLSTATE_DEFAULT in order for the
543 // command line to be used. Therefore, instead of using INSTALLSTATE_ABSENT
544 // to uninstall, we must pass REMOVE=ALL in the command line.
545 CString uninstall_cmd_line;
546 uninstall_cmd_line.Format(_T("REMOVE=ALL %s"),
547 kMsiSuppressAllRebootsCmdLine);
548 UINT res = ::MsiConfigureProductEx(kHelperInstallerProductGuid,
549 INSTALLLEVEL_DEFAULT,
550 INSTALLSTATE_DEFAULT,
551 uninstall_cmd_line);
552
553 // Ignore the product not currently installed result.
554 if ((ERROR_SUCCESS != res) && (ERROR_UNKNOWN_PRODUCT != res)) {
555 HRESULT hr = HRESULT_FROM_WIN32(res);
556 if (FAILED(hr)) {
557 SETUP_LOG(L1, (_T("[MsiInstallProduct failed][0x%08x][%u]"), hr, res));
558 return hr;
559 }
560 }
561
562 return S_OK;
563 }
564
565 HRESULT SetupGoogleUpdate::InstallBrowserPlugins() {
566 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::InstallBrowserPlugins]")));
567 ASSERT1(have_called_uninstall_previous_versions_);
568 // Failure of registration of optional components is acceptable in release
569 // builds.
570 HRESULT hr = S_OK;
571
572 CString plugin_path =
573 BuildSupportFileInstallPath(UPDATE_PLUGIN_FILENAME);
574 hr = RegisterDll(plugin_path);
575 if (FAILED(hr)) {
576 SETUP_LOG(L1, (_T("[Register plugin DLL failed][0x%08x]"), hr));
577 }
578
579 // TODO(omaha): Enable when we ship the BHO.
580 #if 0
581 // Only install the BHO for machine installs. There is no corresponding HKCU
582 // registration for BHOs.
583 if (is_machine_) {
584 CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);
585 hr = RegisterDll(goopdate_bho_proxy_path);
586 if (FAILED(hr)) {
587 SETUP_LOG(L1, (_T("[Register bho_proxy DLL failed][0x%08x]"), hr));
588 }
589 }
590 #endif
591
592 return hr;
593 }
594
595 HRESULT SetupGoogleUpdate::UninstallBrowserPlugins() {
596 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::UninstallBrowserPlugins]")));
597 // Unregistration. Failure is acceptable in release builds.
598 HRESULT hr = S_OK;
599
600 CString plugin_path =
601 BuildSupportFileInstallPath(UPDATE_PLUGIN_FILENAME);
602 hr = UnregisterDll(plugin_path);
603 if (FAILED(hr)) {
604 SETUP_LOG(L1, (_T("[Unregister plugin DLL failed][0x%08x]"), hr));
605 }
606
607 // TODO(omaha): Enable when we ship the BHO.
608 #if 0
609 if (is_machine_) {
610 CString goopdate_bho_proxy_path = BuildSupportFileInstallPath(BHO_FILENAME);
611 hr = UnregisterDll(goopdate_bho_proxy_path);
612 if (FAILED(hr)) {
613 SETUP_LOG(L1, (_T("[Unregister bho_proxy DLL failed][0x%08x]"), hr));
614 }
615 }
616 #endif
617
618 return hr;
619 }
620
621 CString SetupGoogleUpdate::BuildSupportFileInstallPath(
622 const CString& filename) const {
623 SETUP_LOG(L3, (_T("[SetupGoogleUpdate::BuildSupportFileInstallPath][%s]"),
624 filename));
625 CPath install_file_path = goopdate_utils::BuildInstallDirectory(
626 is_machine_,
627 this_version_);
628 VERIFY1(install_file_path.Append(filename));
629
630 return install_file_path;
631 }
632
633 CString SetupGoogleUpdate::BuildCoreProcessCommandLine() const {
634 CString google_update_path =
635 goopdate_utils::BuildGoogleUpdateExePath(is_machine_);
636 CommandLineBuilder builder(COMMANDLINE_MODE_CORE);
637 return builder.GetCommandLine(google_update_path);
638 }
639
640 HRESULT SetupGoogleUpdate::UninstallPreviousVersions() {
641 #ifdef _DEBUG
642 have_called_uninstall_previous_versions_ = true;
643 #endif
644
645 VERIFY1(SUCCEEDED(
646 scheduled_task_utils::UninstallLegacyGoopdateTasks(is_machine_)));
647
648 CString install_path(
649 is_machine_ ? ConfigManager::Instance()->GetMachineGoopdateInstallDir() :
650 ConfigManager::Instance()->GetUserGoopdateInstallDir());
651 SETUP_LOG(L1, (_T("[SetupGoogleUpdate::UninstallPreviousVersions][%s][%s]"),
652 install_path, this_version_));
653 // An empty install_path can be disastrous as it will start deleting from the
654 // current directory.
655 ASSERT1(!install_path.IsEmpty());
656 if (install_path.IsEmpty()) {
657 return E_UNEXPECTED;
658 }
659
660 // In the Google\\Update directory, run over all files and directories.
661 WIN32_FIND_DATA file_data = {0};
662 CPath find_files(install_path);
663 VERIFY1(find_files.Append(_T("*.*")));
664
665 scoped_hfind find_handle(::FindFirstFile(find_files, &file_data));
666 ASSERT1(find_handle);
667 if (!find_handle) {
668 // We should have found ".", "..", and our versioned directory.
669 DWORD err = ::GetLastError();
670 SETUP_LOG(LE, (L"[Subdirs not found under dir][%s][%d]", find_files, err));
671 return HRESULT_FROM_WIN32(err);
672 }
673
674 // Find the rightmost path element of the download directory.
675 CPath download_dir(OMAHA_REL_DOWNLOAD_STORAGE_DIR);
676 download_dir.StripPath();
677
678 BOOL found_next = TRUE;
679 for (; found_next; found_next = ::FindNextFile(get(find_handle),
680 &file_data)) {
681 CPath file_or_directory(install_path);
682 VERIFY1(file_or_directory.Append(file_data.cFileName));
683 if (!(file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
684 // Do not delete the shell as it is used by all versions.
685 if (_tcsicmp(file_data.cFileName, kOmahaShellFileName)) {
686 DeleteBeforeOrAfterReboot(file_or_directory);
687 }
688 } else if (_tcscmp(file_data.cFileName, _T("..")) &&
689 _tcscmp(file_data.cFileName, _T(".")) &&
690 _tcsicmp(file_data.cFileName, this_version_) &&
691 _tcsicmp(file_data.cFileName, download_dir)) {
692 // Unregister the previous version OneClick if it exists. Ignore
693 // failures. The file is named npGoogleOneClick*.dll.
694 CPath old_oneclick(file_or_directory);
695 VERIFY1(old_oneclick.Append(ONECLICK_PLUGIN_NAME _T("*.dll")));
696 WIN32_FIND_DATA old_oneclick_file_data = {};
697 scoped_hfind found_oneclick(::FindFirstFile(old_oneclick,
698 &old_oneclick_file_data));
699 if (found_oneclick) {
700 CPath old_oneclick_file(file_or_directory);
701 VERIFY1(old_oneclick_file.Append(old_oneclick_file_data.cFileName));
702 VERIFY1(SUCCEEDED(UnregisterDll(old_oneclick_file)));
703 }
704
705 // Unregister the previous version of the plugin if it exists. Ignore
706 // failures. The file is named npGoogleUpdate*.dll.
707 CPath old_plugin(file_or_directory);
708 VERIFY1(old_plugin.Append(UPDATE_PLUGIN_NAME _T("*.dll")));
709 WIN32_FIND_DATA old_plugin_file_data = {};
710 scoped_hfind found_plugin(::FindFirstFile(old_plugin,
711 &old_plugin_file_data));
712 if (found_plugin) {
713 CPath old_plugin_file(file_or_directory);
714 VERIFY1(old_plugin_file.Append(old_plugin_file_data.cFileName));
715 VERIFY1(SUCCEEDED(UnregisterDll(old_plugin_file)));
716 }
717
718
719 if (is_machine_) {
720 // TODO(omaha): Enable when we ship the BHO.
721 /*
722 // BHO is only installed for the machine case.
723 // Unregister the previous version BHO if it exists. Ignore failures.
724 CPath old_bho_dll(file_or_directory);
725 VERIFY1(old_bho_dll.Append(BHO_FILENAME));
726 if (File::Exists(old_bho_dll)) {
727 if (FAILED(UnregisterDll(old_bho_dll))) {
728 SETUP_LOG(LW, (L"[UnregisterDll() failed][%s]", old_bho_dll));
729 }
730 }
731 */
732 }
733 // Delete entire sub-directory.
734 DeleteBeforeOrAfterReboot(file_or_directory);
735 }
736 }
737
738 if (!found_next) {
739 DWORD err = ::GetLastError();
740 if (ERROR_NO_MORE_FILES != err) {
741 SETUP_LOG(LE, (L"[::FindNextFile() failed][%d]", err));
742 return HRESULT_FROM_WIN32(err);
743 }
744 }
745
746 // Clean up existing machine ID and user ID since they are no longer used.
747 // Ignore failures as they may not be present and we may not have permission
748 // to HKLM.
749 const TCHAR* const kRegValueMachineId = _T("mi");
750 const TCHAR* const kRegValueUserId = _T("ui");
751 RegKey::DeleteValue(ConfigManager::Instance()->machine_registry_update(),
752 kRegValueMachineId);
753 RegKey::DeleteValue(
754 ConfigManager::Instance()->registry_update(is_machine_),
755 kRegValueUserId);
756
757 return S_OK;
758 }
759
760 void SetupGoogleUpdate::Uninstall() {
761 OPT_LOG(L1, (_T("[SetupGoogleUpdate::Uninstall]")));
762
763 HRESULT hr = UninstallBrowserPlugins();
764 if (FAILED(hr)) {
765 SETUP_LOG(LW, (_T("[UninstallBrowserPlugins failed][0x%08x]"), hr));
766 ASSERT1(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND) == hr);
767 }
768
769 // If running from the installed location instead of a temporary location,
770 // we assume that Omaha had been properly installed and can verify the COM
771 // registration.
772 if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {
773 ASSERT1(SUCCEEDED(VerifyCOMLocalServerRegistration(is_machine_)));
774 }
775
776 hr = RegisterOrUnregisterCOMLocalServer(false);
777 if (FAILED(hr)) {
778 SETUP_LOG(LW,
779 (_T("[RegisterOrUnregisterCOMLocalServer failed][0x%08x]"), hr));
780 ASSERT1(GOOGLEUPDATE_E_DLL_NOT_FOUND == hr ||
781 HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
782 }
783
784 hr = UninstallMsiHelper();
785 if (FAILED(hr)) {
786 SETUP_LOG(L1, (_T("[UninstallMsiHelper failed][0x%08x]"), hr));
787 ASSERT1(HRESULT_FROM_WIN32(ERROR_INSTALL_SERVICE_FAILURE) == hr);
788 }
789
790 UninstallLaunchMechanisms();
791
792 // Remove everything under top level Google Update registry key.
793 hr = DeleteRegistryKeys();
794 ASSERT1(SUCCEEDED(hr) || HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
795 }
796
797 // Also deletes the main Google Update key if there is nothing in it.
798 HRESULT SetupGoogleUpdate::DeleteRegistryKeys() {
799 OPT_LOG(L3, (_T("[SetupGoogleUpdate::DeleteRegistryKeys]")));
800
801 if (is_machine_) {
802 VERIFY1(SUCCEEDED(goopdate_utils::EnableSEHOP(false)));
803 }
804
805 CString root_key = ConfigManager::Instance()->registry_update(is_machine_);
806 ASSERT1(!root_key.IsEmpty());
807
808 RegKey root;
809 HRESULT hr = root.Open(root_key);
810 if (FAILED(hr)) {
811 return hr;
812 }
813
814 std::vector<CString> sub_keys;
815 size_t num_keys = root.GetSubkeyCount();
816 for (size_t i = 0; i < num_keys; ++i) {
817 CString sub_key_name;
818 hr = root.GetSubkeyNameAt(i, &sub_key_name);
819 ASSERT1(hr == S_OK);
820 if (SUCCEEDED(hr)) {
821 sub_keys.push_back(sub_key_name);
822 }
823 }
824
825 ASSERT1(num_keys == sub_keys.size());
826 // Delete all the sub keys of the root key.
827 for (size_t i = 0; i < num_keys; ++i) {
828 VERIFY1(SUCCEEDED(root.RecurseDeleteSubKey(sub_keys[i])));
829 }
830
831 // Now delete all the values of the root key.
832 // The Last* values are not deleted.
833 // TODO(omaha3): The above is a temporary fix for bug 1539293. Need a better
834 // long-term solution in Omaha 3.
835 size_t num_values = root.GetValueCount();
836 std::vector<CString> value_names;
837 for (size_t i = 0; i < num_values; ++i) {
838 CString value_name;
839 DWORD type = 0;
840 hr = root.GetValueNameAt(i, &value_name, &type);
841 ASSERT1(hr == S_OK);
842 // TODO(omaha): Remove kRegValueLast* once we have an install API.
843 if (SUCCEEDED(hr)) {
844 if (value_name != kRegValueUserId &&
845 value_name != kRegValueLastInstallerResult &&
846 value_name != kRegValueLastInstallerError &&
847 value_name != kRegValueLastInstallerExtraCode1 &&
848 value_name != kRegValueLastInstallerResultUIString &&
849 value_name != kRegValueLastInstallerSuccessLaunchCmdLine) {
850 value_names.push_back(value_name);
851 }
852 }
853 }
854
855 for (size_t i = 0; i < value_names.size(); ++i) {
856 VERIFY1(SUCCEEDED(root.DeleteValue(value_names[i])));
857 }
858
859 if (0 == root.GetValueCount() && 0 == root.GetSubkeyCount()) {
860 VERIFY1(SUCCEEDED(RegKey::DeleteKey(root_key, false)));
861 }
862
863 return S_OK;
864 }
865
866 } // namespace omaha
OLDNEW
« no previous file with comments | « setup/setup_google_update.h ('k') | setup/setup_google_update_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698