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