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

Side by Side Diff: setup/setup.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.h ('k') | setup/setup_files.h » ('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-2009 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 // This class handles the installation of Google Update when it is run with the
17 // install or update switch. It is invoked when Google Update is launched from
18 // the meta-installer and as part of self-update.
19
20 #include "omaha/setup/setup.h"
21 #include <regstr.h>
22 #include <atlpath.h>
23 #include <algorithm>
24 #include <functional>
25 #include <vector>
26 #include "omaha/base/const_object_names.h"
27 #include "omaha/base/constants.h"
28 #include "omaha/base/debug.h"
29 #include "omaha/base/error.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/process.h"
34 #include "omaha/base/reg_key.h"
35 #include "omaha/base/scoped_any.h"
36 #include "omaha/base/scope_guard.h"
37 #include "omaha/base/synchronized.h"
38 #include "omaha/base/system.h"
39 #include "omaha/base/timer.h"
40 #include "omaha/base/user_info.h"
41 #include "omaha/base/utils.h"
42 #include "omaha/base/vistautil.h"
43 #include "omaha/common/app_registry_utils.h"
44 #include "omaha/common/command_line.h"
45 #include "omaha/common/config_manager.h"
46 #include "omaha/common/const_cmd_line.h"
47 #include "omaha/common/const_goopdate.h"
48 #include "omaha/common/event_logger.h"
49 #include "omaha/common/goopdate_utils.h"
50 #include "omaha/common/ping.h"
51 #include "omaha/common/scheduled_task_utils.h"
52 #include "omaha/common/stats_uploader.h"
53 #include "omaha/setup/setup_files.h"
54 #include "omaha/setup/setup_google_update.h"
55 #include "omaha/setup/setup_metrics.h"
56 #include "omaha/setup/setup_service.h"
57
58 namespace omaha {
59
60 namespace {
61
62 const TCHAR* const kUninstallEventDescriptionFormat = _T("%s uninstall");
63
64 const int kVersion12 = 12;
65
66 void GetShutdownEventAttributes(bool is_machine, NamedObjectAttributes* attr) {
67 ASSERT1(attr);
68 GetNamedObjectAttributes(kShutdownEvent, is_machine, attr);
69 }
70
71 // Returns the process's mode based on its command line.
72 HRESULT GetProcessModeFromPid(uint32 pid, CommandLineMode* mode) {
73 ASSERT1(mode);
74
75 CString cmd_line;
76 HRESULT hr = Process::GetCommandLine(pid, &cmd_line);
77 if (FAILED(hr)) {
78 SETUP_LOG(LE, (_T("[GetCommandLine failed][%u][0x%08x]"), pid, hr));
79 return hr;
80 }
81
82 CommandLineArgs args;
83 hr = ParseCommandLine(cmd_line, &args);
84 if (FAILED(hr)) {
85 SETUP_LOG(LE, (_T("[ParseCommandLine failed][%u][%s][0x%08x]"),
86 pid, cmd_line, hr));
87 return hr;
88 }
89
90 OPT_LOG(L2, (_T("[Process %u][cmd line %s][mode %u]"),
91 pid, cmd_line, args.mode));
92 *mode = args.mode;
93 return S_OK;
94 }
95
96 void IncrementProcessWaitFailCount(CommandLineMode mode) {
97 switch (mode) {
98 case COMMANDLINE_MODE_UNKNOWN:
99 ++metric_setup_process_wait_failed_unknown;
100 break;
101 case COMMANDLINE_MODE_CORE:
102 ++metric_setup_process_wait_failed_core;
103 break;
104 case COMMANDLINE_MODE_REPORTCRASH:
105 ++metric_setup_process_wait_failed_report;
106 break;
107 case COMMANDLINE_MODE_UPDATE:
108 ++metric_setup_process_wait_failed_update;
109 break;
110 case COMMANDLINE_MODE_HANDOFF_INSTALL:
111 ++metric_setup_process_wait_failed_handoff;
112 break;
113 case COMMANDLINE_MODE_UA:
114 ++metric_setup_process_wait_failed_ua;
115 break;
116 case COMMANDLINE_MODE_CODE_RED_CHECK:
117 ++metric_setup_process_wait_failed_cr;
118 break;
119 case COMMANDLINE_MODE_NOARGS:
120 case COMMANDLINE_MODE_SERVICE:
121
122 case COMMANDLINE_MODE_REGSERVER:
123 case COMMANDLINE_MODE_UNREGSERVER:
124 case COMMANDLINE_MODE_NETDIAGS:
125 case COMMANDLINE_MODE_CRASH:
126 case COMMANDLINE_MODE_INSTALL:
127 case COMMANDLINE_MODE_RECOVER:
128 case COMMANDLINE_MODE_WEBPLUGIN:
129 case COMMANDLINE_MODE_COMSERVER:
130 case COMMANDLINE_MODE_REGISTER_PRODUCT:
131 case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
132 case COMMANDLINE_MODE_SERVICE_REGISTER:
133 case COMMANDLINE_MODE_SERVICE_UNREGISTER:
134 case COMMANDLINE_MODE_CRASH_HANDLER:
135 case COMMANDLINE_MODE_COMBROKER:
136 case COMMANDLINE_MODE_ONDEMAND:
137 case COMMANDLINE_MODE_MEDIUM_SERVICE:
138 case COMMANDLINE_MODE_UNINSTALL:
139 case COMMANDLINE_MODE_PING:
140 default:
141 ++metric_setup_process_wait_failed_other;
142 break;
143 }
144 }
145
146 // Returns the pids of all other GoogleUpdate.exe processes with the specified
147 // argument string. Checks processes for all users that it has privileges to
148 // access.
149 HRESULT GetPidsWithArgsForAllUsers(const CString& args,
150 std::vector<uint32>* pids) {
151 ASSERT1(pids);
152
153 std::vector<CString> command_line;
154 command_line.push_back(args);
155
156 DWORD flags = EXCLUDE_CURRENT_PROCESS |
157 INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
158 HRESULT hr = Process::FindProcesses(flags,
159 kOmahaShellFileName,
160 true,
161 CString(),
162 command_line,
163 pids);
164 if (FAILED(hr)) {
165 SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
166 return hr;
167 }
168
169 return S_OK;
170 }
171
172 void WriteGoogleUpdateUninstallEvent(bool is_machine) {
173 CString description;
174 description.Format(kUninstallEventDescriptionFormat, kAppName);
175 GoogleUpdateLogEvent uninstall_event(EVENTLOG_INFORMATION_TYPE,
176 kUninstallEventId,
177 is_machine);
178 uninstall_event.set_event_desc(description);
179 uninstall_event.WriteEvent();
180 }
181
182 // TODO(omaha3): Enable. Will we still need this method?
183 // Returns true if the mode can be determined and pid represents a "/c" process.
184 bool IsCoreProcess(uint32 pid) {
185 CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
186 return SUCCEEDED(GetProcessModeFromPid(pid, &mode)) &&
187 COMMANDLINE_MODE_CORE == mode;
188 }
189
190 } // namespace
191
192 bool Setup::did_uninstall_ = false;
193
194 Setup::Setup(bool is_machine)
195 : is_machine_(is_machine),
196 is_self_update_(false),
197 extra_code1_(S_OK) {
198 SETUP_LOG(L2, (_T("[Setup::Setup]")));
199 }
200
201 Setup::~Setup() {
202 SETUP_LOG(L2, (_T("[Setup::~Setup]")));
203 }
204
205 // Protects all setup-related operations with:
206 // * Setup Lock - Prevents other instances from installing Google Update for
207 // this machine/user at the same time.
208 // * Shutdown Event - Tells existing other instances and any instances that may
209 // start during Setup to exit.
210 // Setup-related operations do not include installation of the app.
211 HRESULT Setup::Install(bool set_keepalive) {
212 SETUP_LOG(L3,
213 (_T("[Admin=%d, NEAdmin=%d, Update3Svc=%d, MedSvc=%d, Machine=%d"),
214 vista_util::IsUserAdmin(),
215 vista_util::IsUserNonElevatedAdmin(),
216 SetupUpdate3Service::IsServiceInstalled(),
217 SetupUpdateMediumService::IsServiceInstalled(),
218 is_machine_));
219
220 ASSERT1(!IsElevationRequired());
221
222 // Start the setup timer.
223 metrics_timer_.reset(new HighresTimer);
224
225 GLock setup_lock;
226
227 if (!InitSetupLock(is_machine_, &setup_lock)) {
228 SETUP_LOG(L2, (_T("[Setup::InitSetupLock failed]")));
229 extra_code1_ = kVersion12;
230 return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;
231 }
232
233 HighresTimer lock_metrics_timer;
234
235 if (!setup_lock.Lock(kSetupLockWaitMs)) {
236 OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
237 return HandleLockFailed(kVersion12);
238 }
239 metric_setup_lock_acquire_ms.AddSample(lock_metrics_timer.GetElapsedMs());
240 SETUP_LOG(L1, (_T("[Setup Locks acquired]")));
241
242 HRESULT hr = DoProtectedInstall(set_keepalive);
243 if (FAILED(hr)) {
244 SETUP_LOG(LE, (_T("[Setup::DoProtectedInstall failed][0x%08x]"), hr));
245 }
246
247 SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));
248 return hr;
249 }
250
251 // TODO(omaha3): Eliminate lock_version if we do not fix http://b/1076207.
252 // Sets appropriate metrics and extra_code1_ value. It then tries to determine
253 // the scenario that caused this failure and returns an appropriate error.
254 // The detected processes may not actually be in conflict with this one, but are
255 // more than likely the cause of the lock failure.
256 HRESULT Setup::HandleLockFailed(int lock_version) {
257 ++metric_setup_locks_failed;
258
259 switch (lock_version) {
260 case kVersion12:
261 extra_code1_ = kVersion12;
262 ++metric_setup_lock12_failed;
263 break;
264 default:
265 ASSERT1(false);
266 extra_code1_ = -1;
267 break;
268 }
269
270 Pids matching_pids;
271 CString switch_to_include;
272
273 switch_to_include.Format(_T("/%s"), kCmdLineUpdate);
274 HRESULT hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
275 if (FAILED(hr)) {
276 ASSERT1(false);
277 return GOOPDATE_E_FAILED_TO_GET_LOCK;
278 }
279 if (!matching_pids.empty()) {
280 return GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING;
281 }
282
283 switch_to_include.Format(_T("/%s"), kCmdLineUninstall);
284 hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
285 if (FAILED(hr)) {
286 ASSERT1(false);
287 return GOOPDATE_E_FAILED_TO_GET_LOCK;
288 }
289 if (!matching_pids.empty()) {
290 return GOOPDATE_E_FAILED_TO_GET_LOCK_UNINSTALL_PROCESS_RUNNING;
291 }
292
293 switch_to_include.Format(_T("/%s"), kCmdLineInstall);
294 hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
295 if (FAILED(hr)) {
296 ASSERT1(false);
297 return GOOPDATE_E_FAILED_TO_GET_LOCK;
298 }
299 if (matching_pids.empty()) {
300 return GOOPDATE_E_FAILED_TO_GET_LOCK;
301 }
302
303 // Another /install process was found. Determine if it has the same cmd line.
304 const TCHAR* this_cmd_line = ::GetCommandLine();
305 if (!this_cmd_line) {
306 ASSERT1(false);
307 return GOOPDATE_E_FAILED_TO_GET_LOCK;
308 }
309 const CString current_cmd_line(this_cmd_line);
310 if (current_cmd_line.IsEmpty()) {
311 ASSERT1(false);
312 return GOOPDATE_E_FAILED_TO_GET_LOCK;
313 }
314
315 // Strip the directory path, which may vary, and executable name.
316 int exe_index = current_cmd_line.Find(kOmahaShellFileName);
317 if (-1 == exe_index) {
318 ASSERT(false, (_T("Unable to find %s in %s"),
319 kOmahaShellFileName, current_cmd_line));
320 return GOOPDATE_E_FAILED_TO_GET_LOCK;
321 }
322 int args_start = exe_index + _tcslen(kOmahaShellFileName);
323 // Support enclosed paths; increment past closing double quote.
324 if (_T('"') == current_cmd_line.GetAt(args_start)) {
325 ++args_start;
326 }
327 const int args_length = current_cmd_line.GetLength() - args_start;
328 CString current_args = current_cmd_line.Right(args_length);
329 current_args.Trim();
330
331 for (size_t i = 0; i < matching_pids.size(); ++i) {
332 CString matching_pid_cmd_line;
333 if (FAILED(Process::GetCommandLine(matching_pids[i],
334 &matching_pid_cmd_line))) {
335 continue;
336 }
337
338 if (-1 != matching_pid_cmd_line.Find(current_args)) {
339 // Assume that this is a match and not a subset.
340 return GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING;
341 }
342 }
343
344 return GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING;
345 }
346
347 // Assumes the necessary locks have been acquired.
348 HRESULT Setup::DoProtectedInstall(bool set_keepalive) {
349 SETUP_LOG(L2, (_T("[Setup::DoProtectedInstall]")));
350
351 SetupFiles setup_files(is_machine_);
352
353 HRESULT hr = setup_files.Init();
354 if (FAILED(hr)) {
355 SETUP_LOG(LE, (_T("[SetupFiles::Init failed][0x%08x]"), hr));
356 return hr;
357 }
358
359 if (ShouldInstall(&setup_files)) {
360 ++metric_setup_do_self_install_total;
361
362 // TODO(omaha3): IMPORTANT: Try to avoid losing users due to firewall
363 // blocking caused by changing the constant shell. Try a simple ping using
364 // the new shell, and if it fails take one of the following actions:
365 // 1) Keep the old shell (if possible).
366 // 2) Fail the self-update. Leave the user on this version. Would need to
367 // figure out a way to avoid updating the user every 5 hours.
368
369 HRESULT hr = DoProtectedGoogleUpdateInstall(&setup_files);
370 if (FAILED(hr)) {
371 SETUP_LOG(LE, (_T("[DoProtectedGoogleUpdateInstall fail][0x%08x]"), hr));
372 // Do not return until rolling back and releasing the events.
373 }
374
375 if (FAILED(hr)) {
376 RollBack(&setup_files);
377 }
378
379 // We need to hold the shutdown events until phase 2 is complete.
380 // Phase 2 will release the current version's event. Here we release all
381 // shutdown events, including the one that should have already been released
382 // to be safe (i.e. in case phase 2 crashes).
383 // This will happen before the Setup Lock is released, preventing any races.
384 ReleaseShutdownEvents();
385
386 if (FAILED(hr)) {
387 return hr;
388 }
389
390 // If we've been asked to defer uninstall (typically because we're doing
391 // an Omaha-only install to expose the COM API to a later process), set
392 // it on a successful install.
393 if (set_keepalive) {
394 SetDelayUninstall(true);
395 }
396
397 ++metric_setup_do_self_install_succeeded;
398 }
399
400 return S_OK;
401 }
402
403 // Assumes that the shell is the correct version for the existing Omaha version.
404 bool Setup::ShouldInstall(SetupFiles* setup_files) {
405 SETUP_LOG(L2, (_T("[Setup::ShouldInstall]")));
406 ASSERT1(setup_files);
407
408 // TODO(omaha3): Figure out a different way to record these stats.
409 bool is_install = true;
410
411 ++metric_setup_should_install_total;
412
413 ULONGLONG my_version = GetVersion();
414
415 const ConfigManager* cm = ConfigManager::Instance();
416 CString existing_version;
417 HRESULT hr = RegKey::GetValue(cm->registry_clients_goopdate(is_machine_),
418 kRegValueProductVersion,
419 &existing_version);
420 if (FAILED(hr)) {
421 OPT_LOG(L2, (_T("[fresh install]")));
422 ++metric_setup_should_install_true_fresh_install;
423 return true;
424 }
425
426 OPT_LOG(L2, (_T("[Existing version: %s][Running version: %s]"),
427 existing_version, GetVersionString()));
428
429 // If running from the official install directory for this type of install
430 // (user/machine), it is most likely a OneClick install. Do not install self.
431 if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {
432 ++metric_setup_should_install_false_oc;
433 return false;
434 }
435
436 if (is_install) {
437 ++metric_setup_subsequent_install_total;
438 }
439
440 bool should_install(false);
441
442 ULONGLONG cv = VersionFromString(existing_version);
443 if (cv > my_version) {
444 SETUP_LOG(L2, (_T("[not installing, newer version exists]")));
445 ++metric_setup_should_install_false_older;
446 should_install = false;
447 } else if (cv < my_version) {
448 SETUP_LOG(L2, (_T("[installing with local build]")));
449 ++metric_setup_should_install_true_newer;
450 should_install = true;
451 } else {
452 // Same version.
453 should_install = ShouldOverinstallSameVersion(setup_files);
454 if (should_install) {
455 ++metric_setup_should_install_true_same;
456 } else {
457 ++metric_setup_should_install_false_same;
458 }
459 }
460
461 if (is_install && should_install) {
462 ++metric_setup_subsequent_install_should_install_true;
463 }
464
465 OPT_LOG(L1, (_T("[machine = %d][existing version = %s][should_install = %d]"),
466 is_machine_, existing_version, should_install));
467
468 return should_install;
469 }
470
471 // Checks the following:
472 // * OverInstall override.
473 // * The "installed" version in the registry equals this version.
474 // If not, this version was not fully installed even though "pv" says it is.
475 // * Files are properly installed.
476 bool Setup::ShouldOverinstallSameVersion(SetupFiles* setup_files) {
477 SETUP_LOG(L2, (_T("[Setup::ShouldOverinstallSameVersion]")));
478 ASSERT1(setup_files);
479
480 const ConfigManager* cm = ConfigManager::Instance();
481
482 bool should_over_install = cm->CanOverInstall();
483 SETUP_LOG(L1, (_T("[should over install = %d]"), should_over_install));
484 if (should_over_install) {
485 SETUP_LOG(L2, (_T("[overinstalling with local build]")));
486 return true;
487 }
488
489 CString installed_version;
490 HRESULT hr = RegKey::GetValue(cm->registry_update(is_machine_),
491 kRegValueInstalledVersion,
492 &installed_version);
493 if (FAILED(hr) || GetVersionString() != installed_version) {
494 SETUP_LOG(L1, (_T("[installed version missing or did not match][%s]"),
495 installed_version));
496 ++metric_setup_should_install_true_same_completion_missing;
497 return true;
498 }
499
500 if (setup_files->ShouldOverinstallSameVersion()) {
501 SETUP_LOG(L1, (_T("[files need over-install]")));
502 return true;
503 }
504
505 // TODO(omaha): Verify the current installation is complete and correct.
506 // For example, in Omaha 1, we would always set the run key to the version
507 // being installed. Now that code is in SetupGoogleUpdate, and it does not get
508 // called.
509
510 return false;
511 }
512
513 HRESULT Setup::DoProtectedGoogleUpdateInstall(SetupFiles* setup_files) {
514 ASSERT1(setup_files);
515 SETUP_LOG(L2, (_T("[Setup::DoProtectedGoogleUpdateInstall]")));
516
517 HRESULT hr = StopGoogleUpdateAndWait();
518 if (FAILED(hr)) {
519 SETUP_LOG(LE, (_T("[StopGoogleUpdateAndWait failed][0x%08x]"), hr));
520 if (E_ACCESSDENIED == hr) {
521 return GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES;
522 }
523 return hr;
524 }
525
526 // TODO(omaha3): Enable. Prefer to move out of Setup if possible.
527 #if 0
528 VERIFY1(SUCCEEDED(ResetMetrics(is_machine_)));
529 #endif
530
531 hr = RegKey::GetValue(
532 ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
533 kRegValueProductVersion,
534 &saved_version_);
535 if (FAILED(hr)) {
536 SETUP_LOG(L3, (_T("[failed to get existing Omaha version][0x%08x]"), hr));
537 // Continue as this is expected for first installs.
538 }
539
540 hr = setup_files->Install();
541 if (FAILED(hr)) {
542 SETUP_LOG(LE, (_T("[SetupFiles::Install failed][0x%08x]"), hr));
543 extra_code1_ =
544 setup_files->extra_code1() | PingEvent::kSetupFilesExtraCodeMask;
545 return hr;
546 }
547
548 hr = SetupGoogleUpdate();
549 if (FAILED(hr)) {
550 SETUP_LOG(LE, (_T("[SetupGoogleUpdate failed][0x%08x]"), hr));
551 return hr;
552 }
553
554 // TODO(omaha3): Maybe move out of Setup.
555 metric_setup_install_google_update_total_ms.AddSample(
556 metrics_timer_->GetElapsedMs());
557
558 return S_OK;
559 }
560
561 void Setup::RollBack(SetupFiles* setup_files) {
562 OPT_LOG(L1, (_T("[Roll back]")));
563 ASSERT1(setup_files);
564
565 // Restore the saved version.
566 if (!saved_version_.IsEmpty()) {
567 SETUP_LOG(L1, (_T("[Rolling back version to %s]"), saved_version_));
568 ++metric_setup_rollback_version;
569
570 VERIFY1(SUCCEEDED(RegKey::SetValue(
571 ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
572 kRegValueProductVersion,
573 saved_version_)));
574 }
575
576 // TODO(omaha3): Rollback SetupGoogleUpdate.
577 VERIFY1(SUCCEEDED(setup_files->RollBack()));
578 }
579
580 // Assumes the caller is ensuring this is the only running instance of setup.
581 // The original process holds the lock while it waits for this one to complete.
582 HRESULT Setup::SetupGoogleUpdate() {
583 SETUP_LOG(L2, (_T("[Setup::SetupGoogleUpdate]")));
584
585 HighresTimer phase2_metrics_timer;
586
587 omaha::SetupGoogleUpdate setup_google_update(is_machine_);
588
589 HRESULT hr = setup_google_update.FinishInstall();
590 if (FAILED(hr)) {
591 extra_code1_ = setup_google_update.extra_code1();
592 SETUP_LOG(LE, (_T("[FinishInstall failed][0x%x][0x%x]"), hr, extra_code1_));
593 return hr;
594 }
595
596 // Release the shutdown event so that we can start the core if necessary, and
597 // we do not interfere with other app installs that may be waiting on the
598 // Setup Lock.
599 ASSERT1(shutdown_event_);
600 ReleaseShutdownEvents();
601
602 if (!scheduled_task_utils::IsUATaskHealthy(is_machine_)) {
603 HRESULT start_hr = StartCore();
604 if (FAILED(start_hr)) {
605 SETUP_LOG(LW, (_T("[StartCore failed][0x%x]"), start_hr));
606 }
607 }
608
609 // Registration of browser plugins is only done after the shutdown event has
610 // been released; this prevents race conditions where a browser could start
611 // a new install while the shutdown event was still being held.
612 HRESULT plugin_hr = setup_google_update.InstallBrowserPlugins();
613 if (FAILED(plugin_hr)) {
614 SETUP_LOG(LE, (_T("[InstallBrowserPlugins failed][0x%08x]"), plugin_hr));
615 }
616
617 // Setup is now complete.
618
619 metric_setup_phase2_ms.AddSample(phase2_metrics_timer.GetElapsedMs());
620 return S_OK;
621 }
622
623 // Stops all user/machine instances including the service, unregisters using
624 // SetupGoogleUpdate, then deletes the files using SetupFiles.
625 // Does not wait for the processes to exit, except the service.
626 // Protects all operations with the setup lock. If MSI is found busy, Omaha
627 // won't uninstall.
628 HRESULT Setup::Uninstall(bool send_uninstall_ping) {
629 OPT_LOG(L1, (_T("[Setup::Uninstall]")));
630 ASSERT1(!IsElevationRequired());
631
632 // Try to get the global setup lock; if the lock is taken, do not block
633 // waiting to uninstall; just return.
634 GLock setup_lock;
635 VERIFY1(InitSetupLock(is_machine_, &setup_lock));
636 if (!setup_lock.Lock(0)) {
637 OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
638 return E_FAIL;
639 }
640
641 return DoProtectedUninstall(send_uninstall_ping);
642 }
643
644 // Aggregates metrics regardless of whether uninstall is allowed.
645 // Foces reporting of the metrics if uninstall is allowed.
646 // Assumes that the current process holds the Setup Lock.
647 HRESULT Setup::DoProtectedUninstall(bool send_uninstall_ping) {
648 const bool can_uninstall = CanUninstallGoogleUpdate();
649 OPT_LOG(L1, (_T("[CanUninstallGoogleUpdate returned %d]"), can_uninstall));
650
651 HRESULT hr = S_OK;
652 if (!can_uninstall) {
653 hr = GOOPDATE_E_CANT_UNINSTALL;
654 } else {
655 hr = StopGoogleUpdateAndWait();
656 if (FAILED(hr)) {
657 // If there are any clients that don't listen to the shutdown event,
658 // such as the current Update3Web workers, we'll need to wait until
659 // they can be shut down.
660 // TODO(omaha3): We might want to add a count metric for this case,
661 // and maybe go through with the uninstall anyways after several tries.
662 SETUP_LOG(L1, (_T("[StopGoogleUpdateAndWait returned 0x%08x]"), hr));
663 hr = GOOPDATE_E_CANT_UNINSTALL;
664 }
665 }
666
667 if (FAILED(hr)) {
668 VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
669 return hr;
670 }
671 hr = AggregateAndReportMetrics(is_machine_, true);
672 ASSERT1(SUCCEEDED(hr) || GOOPDATE_E_CANNOT_USE_NETWORK == hr);
673
674 bool can_use_network = ConfigManager::Instance()->CanUseNetwork(is_machine_);
675 if (can_use_network && send_uninstall_ping) {
676 SendUninstallPing();
677 }
678
679 // Write the event in the event log before uninstalling the program since
680 // the event contains version and language information, which are removed
681 // during the uninstall.
682 WriteGoogleUpdateUninstallEvent(is_machine_);
683
684 omaha::SetupGoogleUpdate setup_google_update(is_machine_);
685 setup_google_update.Uninstall();
686
687 SetupFiles setup_files(is_machine_);
688 setup_files.Uninstall();
689
690 OPT_LOG(L1, (_T("[Uninstall complete]")));
691 did_uninstall_ = true;
692 return S_OK;
693 }
694
695 // Should only be called after the point where Uninstall would have been called.
696 // Works correctly in the case where the Setup Lock is not held but an app is
697 // being installed because it does not check the number of registered apps.
698 // Either Omaha is installed or has been cleaned up.
699 // Installed means Clients, ClientState, etc. sub keys exist.
700 // Cleaned up may mean the Update key does not exist or some values, such as
701 // mid and uid exist, but there are no subkeys.
702 // The Update key should never exist without any values.
703 // Does not take the Setup Lock because it is just a dbg check. It is possible
704 // for the value of did_uninstall_ to be changed in another thread or for
705 // another process to install or uninstall Google Update while this is running.
706 void Setup::CheckInstallStateConsistency(bool is_machine) {
707 UNREFERENCED_PARAMETER(is_machine);
708 #if DEBUG
709 CString key_name = ConfigManager::Instance()->registry_update(is_machine);
710 if (!RegKey::HasKey(key_name)) {
711 // Either this instance called uninstall or it is the non-elevated machine
712 // instance on Vista and later. Both cannot be true in the same instance.
713 ASSERT1(did_uninstall_ != (is_machine && !vista_util::IsUserAdmin()));
714 return;
715 }
716
717 RegKey update_key;
718 ASSERT1(SUCCEEDED(update_key.Open(key_name, KEY_READ)));
719
720 ASSERT1(0 != update_key.GetValueCount());
721
722 if (did_uninstall_) {
723 ASSERT1(0 == update_key.GetSubkeyCount());
724 ASSERT1(!update_key.HasValue(kRegValueInstalledVersion));
725 ASSERT1(!update_key.HasValue(kRegValueInstalledPath));
726 } else {
727 ASSERT1(update_key.HasSubkey(_T("Clients")));
728 ASSERT1(update_key.HasSubkey(_T("ClientState")));
729 ASSERT1(update_key.HasSubkey(_T("network")));
730 ASSERT1(update_key.HasValue(kRegValueInstalledVersion));
731 ASSERT1(update_key.HasValue(kRegValueInstalledPath));
732
733 CString installed_version;
734 ASSERT1(SUCCEEDED(update_key.GetValue(kRegValueInstalledVersion,
735 &installed_version)));
736 const CString state_key_name =
737 ConfigManager::Instance()->registry_client_state_goopdate(is_machine);
738 CString pv;
739 ASSERT1(SUCCEEDED(RegKey::GetValue(state_key_name,
740 kRegValueProductVersion,
741 &pv)));
742 ASSERT1(installed_version == pv);
743 }
744 #endif
745 }
746
747 // Stops both legacy and current instances.
748 // Holds the shutdown events so that other instances do not start running.
749 // The caller is responsible for releasing the events.
750 // Because this waiting occurs before a UI is generated, we do not want to wait
751 // too long.
752 HRESULT Setup::StopGoogleUpdate() {
753 OPT_LOG(L1, (_T("[Stopping other instances]")));
754
755 HRESULT hr = SignalShutdownEvent();
756 if (FAILED(hr)) {
757 SETUP_LOG(LE, (_T("[SignalShutdownEvent failed][0x%08x]"), hr));
758 return hr;
759 }
760
761 return S_OK;
762 }
763
764 HRESULT Setup::StopGoogleUpdateAndWait() {
765 HRESULT hr = StopGoogleUpdate();
766 if (FAILED(hr)) {
767 SETUP_LOG(LE, (_T("[StopGoogleUpdate failed][0x%08x]"), hr));
768 return hr;
769 }
770
771 Pids pids;
772 hr = GetPidsToWaitFor(&pids);
773 if (FAILED(hr)) {
774 SETUP_LOG(LEVEL_ERROR, (_T("[GetPidsToWaitFor failed][0x%08x]"), hr));
775 return hr;
776 }
777
778 hr = WaitForOtherInstancesToExit(pids);
779 if (FAILED(hr)) {
780 SETUP_LOG(LE, (_T("[WaitForOtherInstancesToExit failed][0x%08x]"), hr));
781 return hr;
782 }
783
784 return S_OK;
785 }
786
787 // Signals >= 1.2.x processes to exit.
788 HRESULT Setup::SignalShutdownEvent() {
789 SETUP_LOG(L1, (_T("[Setup::SignalShutdownEvent]")));
790 NamedObjectAttributes event_attr;
791 GetShutdownEventAttributes(is_machine_, &event_attr);
792
793 if (!shutdown_event_) {
794 HRESULT hr = goopdate_utils::CreateEvent(&event_attr,
795 address(shutdown_event_));
796 if (FAILED(hr)) {
797 SETUP_LOG(LE, (_T("[CreateEvent current failed][0x%08x]"), hr));
798 return hr;
799 }
800 }
801
802 VERIFY1(::SetEvent(get(shutdown_event_)));
803
804 return S_OK;
805 }
806
807 void Setup::ReleaseShutdownEvents() {
808 if (!shutdown_event_) {
809 return;
810 }
811
812 VERIFY1(::ResetEvent(get(shutdown_event_)));
813 reset(shutdown_event_);
814 }
815
816 // Because this waiting can occur before a UI is generated, we do not want to
817 // wait too long.
818 // If a process fails to stop, its mode is stored in extra_code1_.
819 // Does not return until all opened handles have been closed.
820 // TODO(omaha): Add a parameter to specify the amount of time to wait to this
821 // method and StopGoogleUpdateAndWait after we unify Setup and always have a UI.
822 HRESULT Setup::WaitForOtherInstancesToExit(const Pids& pids) {
823 OPT_LOG(L1, (_T("[Waiting for other instances to exit]")));
824
825 // Wait for all the processes to exit.
826 std::vector<HANDLE> handles;
827 for (size_t i = 0; i < pids.size(); ++i) {
828 SETUP_LOG(L2, (_T("[Waiting for process][%u]"), pids[i]));
829
830 DWORD desired_access =
831 PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;
832 scoped_handle handle(::OpenProcess(desired_access,
833 FALSE,
834 pids[i]));
835 if (!handle) {
836 HRESULT hr = HRESULTFromLastError();
837 SETUP_LOG(LE, (_T("[::OpenProcess failed][%u][0x%08x]"), pids[i], hr));
838 continue;
839 }
840
841 handles.push_back(release(handle));
842 }
843
844 HRESULT hr = S_OK;
845 if (!handles.empty()) {
846 SETUP_LOG(L2, (_T("[Calling ::WaitForMultipleObjects]")));
847
848 HighresTimer metrics_timer;
849 const int wait_ms = is_self_update_ ? kSetupUpdateShutdownWaitMs :
850 kSetupInstallShutdownWaitMs;
851 DWORD res = ::WaitForMultipleObjects(handles.size(),
852 &handles.front(),
853 true, // wait for all
854 wait_ms);
855 metric_setup_process_wait_ms.AddSample(metrics_timer.GetElapsedMs());
856
857 SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
858 ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
859 if (WAIT_FAILED == res) {
860 const DWORD error = ::GetLastError();
861 SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
862 hr = HRESULT_FROM_WIN32(error);
863 } else if (WAIT_OBJECT_0 != res) {
864 OPT_LOG(LEVEL_ERROR, (_T("[Other GoogleUpdate.exe instances failed to ")
865 _T("shutdown in time][%u]"), res));
866
867 extra_code1_ = COMMANDLINE_MODE_UNKNOWN;
868
869 SETUP_LOG(L2, (_T("[Listing processes that did not exit. This may be ")
870 _T("incomplete if processes exited after ")
871 _T("WaitForMultipleObjects returned.]")));
872 for (size_t i = 0; i < handles.size(); ++i) {
873 if (WAIT_TIMEOUT == ::WaitForSingleObject(handles[i], 0)) {
874 uint32 pid = Process::GetProcessIdFromHandle(handles[i]);
875 if (!pid) {
876 SETUP_LOG(LW, (_T(" [Process::GetProcessIdFromHandle failed][%u]"),
877 ::GetLastError()));
878 SETUP_LOG(L2, (_T(" [Process did not exit][unknown]")));
879 continue;
880 }
881 SETUP_LOG(L2, (_T(" [Process did not exit][%u]"), pid));
882
883 CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
884 if (SUCCEEDED(GetProcessModeFromPid(pid, &mode))) {
885 extra_code1_ = mode;
886 }
887 IncrementProcessWaitFailCount(mode);
888 }
889 }
890
891 ++metric_setup_process_wait_failed;
892 hr = GOOPDATE_E_INSTANCES_RUNNING;
893 }
894 }
895 if (SUCCEEDED(hr)) {
896 SETUP_LOG(L3, (_T("[Wait for all processes to exit succeeded]")));
897 } else {
898 for (size_t i = 0; i < handles.size(); ++i) {
899 if (!::TerminateProcess(handles[i], UINT_MAX)) {
900 const uint32 pid = Process::GetProcessIdFromHandle(handles[i]);
901 const DWORD error = ::GetLastError();
902 SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"), pid, error));
903 }
904 }
905
906 const int kTerminateWaitMs = 500;
907 DWORD res = ::WaitForMultipleObjects(handles.size(), &handles.front(),
908 true, kTerminateWaitMs);
909 if (res != WAIT_OBJECT_0) {
910 const DWORD error = ::GetLastError();
911 SETUP_LOG(LW, (_T("[Wait failed][%u][%u]"), res, error));
912 }
913 }
914
915 // Close the handles.
916 for (size_t i = 0; i < handles.size(); ++i) {
917 if (!::CloseHandle(handles[i])) {
918 HRESULT hr = HRESULTFromLastError();
919 SETUP_LOG(LEVEL_WARNING, (_T("[CloseHandle failed][0x%08x]"), hr));
920 }
921 }
922
923 return S_OK;
924 }
925
926 // Wait for all instances of Omaha running as the current user - or as any user
927 // in the case of machine installs - except "/install" or "/registerproduct"
928 // instances, which should be blocked by the Setup Lock, which we are holding.
929 HRESULT Setup::GetPidsToWaitFor(Pids* pids) const {
930 ASSERT1(pids);
931
932 HRESULT hr = GetPidsToWaitForUsingCommandLine(pids);
933 if (FAILED(hr)) {
934 return hr;
935 }
936
937 ASSERT1(pids->end() == std::find(pids->begin(), pids->end(),
938 ::GetCurrentProcessId()));
939 SETUP_LOG(L3, (_T("[found %d total processes to wait for]"), pids->size()));
940
941 return S_OK;
942 }
943
944 // Finds processes to wait for based on the command line.
945 // Differences between Omaha 2 and this code:
946 // * User's processes running outside AppData are not caught. This should only
947 // be /install or /registerproduct.
948 // * In the user case, "machine" processes running as the user are EXcluded
949 // based on path instead of mode and "needsadmin=true". This additionally
950 // excludes oneclick cross-installs (u-to-m).
951 // * In the machine case, "machine" processes running as the user are INcluded
952 // based on path instead of mode and "needsadmin=true".
953 // * /pi: m-to-u running in PF as user with needsadmin=false: now INcluded.
954 // This is a good idea, since we do not want to delete the in-use file.
955 // /pi: u-to-m running in appdata as user with needsadmin=true: now
956 // EXcluded.
957 HRESULT Setup::GetPidsToWaitForUsingCommandLine(Pids* pids) const {
958 CORE_LOG(L3, (_T("[Setup::GetPidsToWaitForUsingCommandLine]")));
959
960 ASSERT1(pids);
961
962 // Get processes running as the current user in the case of user, and all
963 // users as well as SYSTEM in the case of machine, except those with
964 // * "/install" - must be excluded because may be waiting for the Setup Lock.
965 // * "/registerproduct" - same as for /install.
966 std::vector<CString> command_lines;
967 CString switch_to_exclude;
968 switch_to_exclude.Format(_T("/%s"), kCmdLineInstall);
969 command_lines.push_back(switch_to_exclude);
970 switch_to_exclude.Format(_T("/%s"), kCmdLineRegisterProduct);
971
972 CString user_sid;
973 DWORD flags = EXCLUDE_CURRENT_PROCESS |
974 EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
975
976 if (!is_machine_) {
977 // Search only the same sid as the current user.
978 flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
979
980 HRESULT hr = user_info::GetProcessUser(NULL, NULL, &user_sid);
981 if (FAILED(hr)) {
982 CORE_LOG(LE, (_T("[GetProcessUser failed][0x%x]"), hr));
983 return hr;
984 }
985 }
986
987 std::vector<uint32> google_update_process_ids;
988 HRESULT hr = Process::FindProcesses(flags,
989 kOmahaShellFileName,
990 true,
991 user_sid,
992 command_lines,
993 &google_update_process_ids);
994 if (FAILED(hr)) {
995 CORE_LOG(LE, (_T(" [FindProcesses failed][0x%08x]"), hr));
996 return hr;
997 }
998
999 const ConfigManager* cm = ConfigManager::Instance();
1000 CString official_path(is_machine_ ?
1001 cm->GetMachineGoopdateInstallDirNoCreate() :
1002 cm->GetUserGoopdateInstallDirNoCreate());
1003 ASSERT1(!official_path.IsEmpty());
1004
1005 // Only include processes running under the official path.
1006 Pids pids_to_wait_for;
1007 for (size_t i = 0; i < google_update_process_ids.size(); ++i) {
1008 CString cmd_line;
1009 const uint32 process_id = google_update_process_ids[i];
1010 if (SUCCEEDED(Process::GetCommandLine(process_id, &cmd_line))) {
1011 cmd_line.MakeLower();
1012
1013 CString exe_path;
1014 if (SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) &&
1015 String_StrNCmp(official_path, exe_path, official_path.GetLength(),
1016 true) == 0) {
1017 CORE_LOG(L4, (_T(" [Including pid][%u][%s]"), process_id, cmd_line));
1018 pids_to_wait_for.push_back(process_id);
1019 }
1020 }
1021 }
1022
1023 pids->swap(pids_to_wait_for);
1024 return S_OK;
1025 }
1026
1027 // On Windows Vista, an admin must be elevated in order to install a machine app
1028 // without elevating. On Vista, IsUserAdmin returns false unless the user is
1029 // elevated.
1030 bool Setup::IsElevationRequired() const {
1031 return is_machine_ && !vista_util::IsUserAdmin();
1032 }
1033
1034 // Start the machine core process using one of the launch mechanisms.
1035 // We know that at least one of the service and scheduled task were installed
1036 // because otherwise we would have exited fatally.
1037 // If the service was not installed, starting it will just fail silently and we
1038 // will start the scheduled task.
1039 // do not call this method until the shutdown event has been released or the
1040 // process may immediately exit.
1041 // TODO(omaha): Provide service_hr and task_hr failures in a ping.
1042 HRESULT Setup::StartMachineCoreProcess() const {
1043 SETUP_LOG(L3, (_T("[Setup::StartMachineCoreProcess]")));
1044
1045 HighresTimer metrics_timer;
1046
1047 // Start the service.
1048 ++metric_setup_start_service_total;
1049 HRESULT service_hr = SetupUpdate3Service::StartService();
1050 if (SUCCEEDED(service_hr)) {
1051 metric_setup_start_service_ms.AddSample(metrics_timer.GetElapsedMs());
1052 OPT_LOG(L1, (_T("[Service started]")));
1053 ++metric_setup_start_service_succeeded;
1054 return S_OK;
1055 }
1056 metric_setup_start_service_failed_ms.AddSample(metrics_timer.GetElapsedMs());
1057 OPT_LOG(LEVEL_ERROR, (_T("[Start service failed][0x%08x]"), service_hr));
1058 metric_setup_start_service_error = service_hr;
1059
1060 // TODO(omaha): We should only skip this block when /install /silent fails
1061 // and there are no other apps installed. Guarantee this somehow.
1062 ++metric_setup_start_task_total;
1063 const ULONGLONG start_task_start_ms = metrics_timer.GetElapsedMs();
1064 HRESULT task_hr = scheduled_task_utils::StartGoopdateTaskCore(true);
1065 if (SUCCEEDED(task_hr)) {
1066 const ULONGLONG start_task_end_ms = metrics_timer.GetElapsedMs();
1067 ASSERT1(start_task_end_ms >= start_task_start_ms);
1068 metric_setup_start_task_ms.AddSample(
1069 start_task_end_ms - start_task_start_ms);
1070 OPT_LOG(L1, (_T("[run scheduled task succeeded]")));
1071 ++metric_setup_start_task_succeeded;
1072 return S_OK;
1073 }
1074 OPT_LOG(LE, (_T("[Start scheduled task failed][0x%08x]"), task_hr));
1075 metric_setup_start_task_error = task_hr;
1076
1077 return service_hr;
1078 }
1079
1080 // Start the user core process directly.
1081 // Do not call this method until the shutdown event has been released or the
1082 // process may immediately exit.
1083 HRESULT Setup::StartUserCoreProcess(const CString& core_cmd_line) const {
1084 HRESULT hr = System::StartCommandLine(core_cmd_line);
1085 if (FAILED(hr)) {
1086 SETUP_LOG(LE, (_T("[Could not start Google Update Core][0x%08x]"), hr));
1087 return hr;
1088 }
1089
1090 return S_OK;
1091 }
1092
1093 HRESULT Setup::FindCoreProcesses(Pids* found_core_pids) const {
1094 SETUP_LOG(L3, (_T("[Setup::FindCoreProcesses]")));
1095 ASSERT1(found_core_pids);
1096
1097 CString user_sid;
1098 HRESULT hr = GetAppropriateSid(&user_sid);
1099 if (FAILED(hr)) {
1100 return hr;
1101 }
1102
1103 std::vector<CString> command_lines;
1104 CString switch_to_include;
1105 switch_to_include.Format(_T("/%s"), kCmdLineCore);
1106 command_lines.push_back(switch_to_include);
1107
1108 DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
1109 EXCLUDE_CURRENT_PROCESS |
1110 INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
1111 hr = Process::FindProcesses(flags,
1112 kOmahaShellFileName,
1113 true,
1114 user_sid,
1115 command_lines,
1116 found_core_pids);
1117 if (FAILED(hr)) {
1118 SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
1119 return hr;
1120 }
1121
1122 // Remove PIDs where the command line is not actually the "/c" switch and is
1123 // some other command line, such as "/cr".
1124 const Pids::iterator new_end = std::remove_if(
1125 found_core_pids->begin(),
1126 found_core_pids->end(),
1127 std::not1(std::ptr_fun(IsCoreProcess)));
1128 if (new_end != found_core_pids->end()) {
1129 found_core_pids->erase(new_end, found_core_pids->end());
1130 }
1131
1132 SETUP_LOG(L2, (_T("[Core processes found][%u]"), found_core_pids->size()));
1133 return S_OK;
1134 }
1135
1136 // Does not try to terminate legacy processes.
1137 // Waits up to 500 ms for the terminated core processes to exit.
1138 HRESULT Setup::TerminateCoreProcesses() const {
1139 SETUP_LOG(L2, (_T("[Setup::TerminateCoreProcesses]")));
1140 Pids found_core_pids;
1141 HRESULT hr = FindCoreProcesses(&found_core_pids);
1142 if (FAILED(hr)) {
1143 SETUP_LOG(LE, (_T("[FindCoreProcesses failed][0x%08x]"), hr));
1144 return hr;
1145 }
1146
1147 std::vector<HANDLE> terminated_processes;
1148 for (size_t i = 0; i < found_core_pids.size(); ++i) {
1149 uint32 pid = found_core_pids[i];
1150
1151 SETUP_LOG(L2, (_T("[Terminating core process][%u]"), pid));
1152
1153 HANDLE process(::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid));
1154 if (!process) {
1155 SETUP_LOG(LW, (_T("[::OpenProcess failed][%u][%u]"),
1156 pid, ::GetLastError()));
1157 continue;
1158 }
1159 terminated_processes.push_back(process);
1160
1161 if (!::TerminateProcess(process, static_cast<uint32>(-2))) {
1162 SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"),
1163 pid, ::GetLastError()));
1164 }
1165 }
1166
1167 if (terminated_processes.empty()) {
1168 return S_OK;
1169 }
1170 // Do not return until the handles have been closed.
1171
1172 const int kCoreTerminateWaitMs = 500;
1173 DWORD res = ::WaitForMultipleObjects(terminated_processes.size(),
1174 &terminated_processes.front(),
1175 true, // wait for all
1176 kCoreTerminateWaitMs);
1177 SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
1178 ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
1179 if (WAIT_FAILED == res) {
1180 const DWORD error = ::GetLastError();
1181 SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
1182 hr = HRESULT_FROM_WIN32(error);
1183 } else {
1184 hr = HRESULT_FROM_WIN32(res);
1185 }
1186
1187 for (size_t i = 0; i < terminated_processes.size(); ++i) {
1188 VERIFY1(::CloseHandle(terminated_processes[i]));
1189 }
1190
1191 return hr;
1192 }
1193
1194 // Tries to start the core using existing launch methods if present.
1195 // Uses the service or the scheduled task for machine, and the Run key value for
1196 // user.
1197 HRESULT Setup::StartCore() const {
1198 SETUP_LOG(L2, (_T("[Attempting to start core]")));
1199
1200 if (is_machine_) {
1201 HRESULT hr = StartMachineCoreProcess();
1202 if (FAILED(hr)) {
1203 SETUP_LOG(LW, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));
1204 return hr;
1205 }
1206
1207 return hr;
1208 }
1209
1210 CString installed_run_cmd_line;
1211 HRESULT hr = RegKey::GetValue(USER_KEY REGSTR_PATH_RUN, kRunValueName,
1212 &installed_run_cmd_line);
1213 if (FAILED(hr)) {
1214 SETUP_LOG(LW, (_T("[Failed to get Run val][%s][0x%x]"), kRunValueName, hr));
1215 return hr;
1216 }
1217
1218 hr = StartUserCoreProcess(installed_run_cmd_line);
1219 if (FAILED(hr)) {
1220 SETUP_LOG(LW, (_T("[StartUserCoreProcess failed][%s][0x%x]"),
1221 installed_run_cmd_line, hr));
1222 return hr;
1223 }
1224
1225 return S_OK;
1226 }
1227
1228 // Returns Local System's SID for machine installs and the user's SID otherwise.
1229 HRESULT Setup::GetAppropriateSid(CString* sid) const {
1230 ASSERT1(sid);
1231 if (is_machine_) {
1232 *sid = kLocalSystemSid;
1233 } else {
1234 HRESULT hr = user_info::GetProcessUser(NULL, NULL, sid);
1235 if (FAILED(hr)) {
1236 SETUP_LOG(LEVEL_ERROR, (_T("[GetProcessUser failed][0x%08x]"), hr));
1237 return hr;
1238 }
1239 }
1240
1241 return S_OK;
1242 }
1243
1244 bool Setup::InitSetupLock(bool is_machine, GLock* setup_lock) {
1245 ASSERT1(setup_lock);
1246 NamedObjectAttributes setup_lock_attr;
1247 GetNamedObjectAttributes(kSetupMutex, is_machine, &setup_lock_attr);
1248 return setup_lock->InitializeWithSecAttr(setup_lock_attr.name,
1249 &setup_lock_attr.sa);
1250 }
1251
1252 // Assumes that the Setup Lock is held.
1253 // This method is based on the assumption that if another install, which could
1254 // be modifying the number of clients, is in progress, that it either:
1255 // (a) Has the Setup Lock, which is not possible because this process has it.
1256 // (b) Has started an install worker.
1257 // TODO(omaha3): This is flawed: http://b/2764048.
1258 bool Setup::CanUninstallGoogleUpdate() const {
1259 CORE_LOG(L2, (_T("[Setup::CanUninstallGoogleUpdate]")));
1260 if (goopdate_utils::IsAppInstallWorkerRunning(is_machine_)) {
1261 CORE_LOG(L2, (_T("[Found install workers. Not uninstalling]")));
1262 return false;
1263 }
1264 if (ShouldDelayUninstall()) {
1265 // If the DelayUninstall flag is set, that implies that someone has
1266 // installed us with the runtime=true flag, expecting that they can
1267 // use our API later from another process. If 24 hours have passed
1268 // since that initial Omaha install, we clear the flag but still
1269 // return false for this check. (That way, if a machine has been
1270 // suspended in mid-install, they still have a grace period until
1271 // the next /ua to get something installed.)
1272 CORE_LOG(L3, (_T("[DelayUninstall is set. Not uninstalling.]")));
1273 if (ConfigManager::Instance()->Is24HoursSinceInstall(is_machine_)) {
1274 CORE_LOG(L4, (_T("[24 hours elapsed; clearing DelayUninstall.]")));
1275 SetDelayUninstall(false);
1276 }
1277 return false;
1278 }
1279 size_t num_clients(0);
1280 if (SUCCEEDED(app_registry_utils::GetNumClients(is_machine_, &num_clients)) &&
1281 num_clients >= 2) {
1282 CORE_LOG(L3, (_T("[Found products. Not uninstalling]")));
1283 return false;
1284 }
1285
1286 return true;
1287 }
1288
1289 bool Setup::ShouldDelayUninstall() const {
1290 const TCHAR* key = ConfigManager::Instance()->registry_update(is_machine_);
1291 if (!RegKey::HasValue(key, kRegValueDelayOmahaUninstall)) {
1292 return false;
1293 }
1294 DWORD should_delay = 0;
1295 if (FAILED(RegKey::GetValue(key,
1296 kRegValueDelayOmahaUninstall,
1297 &should_delay))) {
1298 return false;
1299 }
1300 return should_delay != 0;
1301 }
1302
1303 HRESULT Setup::SetDelayUninstall(bool should_delay) const {
1304 const TCHAR* key = ConfigManager::Instance()->registry_update(is_machine_);
1305 if (should_delay) {
1306 return RegKey::SetValue(key, kRegValueDelayOmahaUninstall, 1UL);
1307 } else {
1308 return RegKey::DeleteValue(key, kRegValueDelayOmahaUninstall);
1309 }
1310 }
1311
1312 HRESULT Setup::SendUninstallPing() {
1313 CORE_LOG(L3, (_T("[SendUninstallPing]")));
1314
1315 const bool is_eula_accepted =
1316 app_registry_utils::IsAppEulaAccepted(is_machine_,
1317 kGoogleUpdateAppId,
1318 false);
1319
1320 if (!is_eula_accepted) {
1321 CORE_LOG(LE, (_T("[SendUninstallPing - eula not accepted]")));
1322 return E_FAIL;
1323 }
1324
1325 PingEventPtr uninstall_ping_event(
1326 new PingEvent(PingEvent::EVENT_UNINSTALL,
1327 PingEvent::EVENT_RESULT_SUCCESS,
1328 0,
1329 0));
1330
1331 // Generate a session ID for uninstall pings. NOTE: The assumption here is
1332 // that if /uninstall was launched by /ua, we have no updates to check for,
1333 // so we assume that /ua won't use its own session ID. If /ua does any
1334 // network activity on a no-clients case, we will have to start passing the
1335 // session ID from /ua to /uninstall in the future.
1336 CString session_id;
1337 VERIFY1(SUCCEEDED(GetGuid(&session_id)));
1338
1339 // Send uninstall ping for uninstalled apps.
1340 HRESULT hr = S_OK;
1341 std::vector<CString> uninstalled_apps;
1342 if (SUCCEEDED(app_registry_utils::GetUninstalledApps(is_machine_,
1343 &uninstalled_apps))) {
1344 Ping apps_uninstall_ping(is_machine_, session_id, kInstallSource_Uninstall);
1345 apps_uninstall_ping.LoadAppDataFromRegistry(uninstalled_apps);
1346 apps_uninstall_ping.BuildAppsPing(uninstall_ping_event);
1347
1348 hr = apps_uninstall_ping.Send(false);
1349 if (FAILED(hr)) {
1350 CORE_LOG(LE, (_T("[SendUninstallPing: failed to send app uninstall ping]")
1351 _T("[0x%08x]"), hr));
1352 }
1353 }
1354
1355 // Send uninstall ping for Omaha.
1356 const CString current_omaha_version(GetVersionString());
1357 const CString next_omaha_version; // Empty, in the uninstall case.
1358 Ping omaha_uninstall_ping(is_machine_, session_id, kInstallSource_Uninstall);
1359 omaha_uninstall_ping.LoadOmahaDataFromRegistry();
1360 omaha_uninstall_ping.BuildOmahaPing(current_omaha_version,
1361 next_omaha_version,
1362 uninstall_ping_event);
1363 hr = omaha_uninstall_ping.Send(false);
1364 if (SUCCEEDED(hr)) {
1365 // Clears the registry after ping is sent successfully.
1366 std::vector<CString> uninstalled_apps;
1367 app_registry_utils::GetUninstalledApps(is_machine_, &uninstalled_apps);
1368 app_registry_utils::RemoveClientStateForApps(is_machine_, uninstalled_apps);
1369 } else {
1370 CORE_LOG(LE, (_T("[SendUninstallPing: failed to send Omaha uninstall ping]")
1371 _T("[0x%08x]"), hr));
1372 }
1373
1374 return hr;
1375 }
1376
1377
1378 } // namespace omaha
OLDNEW
« no previous file with comments | « setup/setup.h ('k') | setup/setup_files.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698