| 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 |