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

Unified Diff: setup/setup.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « setup/setup.h ('k') | setup/setup_files.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: setup/setup.cc
diff --git a/setup/setup.cc b/setup/setup.cc
deleted file mode 100644
index fd1a6e686443f361a9d8018194f951c30c0f32e6..0000000000000000000000000000000000000000
--- a/setup/setup.cc
+++ /dev/null
@@ -1,1378 +0,0 @@
-// Copyright 2007-2009 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ========================================================================
-//
-// This class handles the installation of Google Update when it is run with the
-// install or update switch. It is invoked when Google Update is launched from
-// the meta-installer and as part of self-update.
-
-#include "omaha/setup/setup.h"
-#include <regstr.h>
-#include <atlpath.h>
-#include <algorithm>
-#include <functional>
-#include <vector>
-#include "omaha/base/const_object_names.h"
-#include "omaha/base/constants.h"
-#include "omaha/base/debug.h"
-#include "omaha/base/error.h"
-#include "omaha/base/highres_timer-win32.h"
-#include "omaha/base/logging.h"
-#include "omaha/base/omaha_version.h"
-#include "omaha/base/process.h"
-#include "omaha/base/reg_key.h"
-#include "omaha/base/scoped_any.h"
-#include "omaha/base/scope_guard.h"
-#include "omaha/base/synchronized.h"
-#include "omaha/base/system.h"
-#include "omaha/base/timer.h"
-#include "omaha/base/user_info.h"
-#include "omaha/base/utils.h"
-#include "omaha/base/vistautil.h"
-#include "omaha/common/app_registry_utils.h"
-#include "omaha/common/command_line.h"
-#include "omaha/common/config_manager.h"
-#include "omaha/common/const_cmd_line.h"
-#include "omaha/common/const_goopdate.h"
-#include "omaha/common/event_logger.h"
-#include "omaha/common/goopdate_utils.h"
-#include "omaha/common/ping.h"
-#include "omaha/common/scheduled_task_utils.h"
-#include "omaha/common/stats_uploader.h"
-#include "omaha/setup/setup_files.h"
-#include "omaha/setup/setup_google_update.h"
-#include "omaha/setup/setup_metrics.h"
-#include "omaha/setup/setup_service.h"
-
-namespace omaha {
-
-namespace {
-
-const TCHAR* const kUninstallEventDescriptionFormat = _T("%s uninstall");
-
-const int kVersion12 = 12;
-
-void GetShutdownEventAttributes(bool is_machine, NamedObjectAttributes* attr) {
- ASSERT1(attr);
- GetNamedObjectAttributes(kShutdownEvent, is_machine, attr);
-}
-
-// Returns the process's mode based on its command line.
-HRESULT GetProcessModeFromPid(uint32 pid, CommandLineMode* mode) {
- ASSERT1(mode);
-
- CString cmd_line;
- HRESULT hr = Process::GetCommandLine(pid, &cmd_line);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[GetCommandLine failed][%u][0x%08x]"), pid, hr));
- return hr;
- }
-
- CommandLineArgs args;
- hr = ParseCommandLine(cmd_line, &args);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[ParseCommandLine failed][%u][%s][0x%08x]"),
- pid, cmd_line, hr));
- return hr;
- }
-
- OPT_LOG(L2, (_T("[Process %u][cmd line %s][mode %u]"),
- pid, cmd_line, args.mode));
- *mode = args.mode;
- return S_OK;
-}
-
-void IncrementProcessWaitFailCount(CommandLineMode mode) {
- switch (mode) {
- case COMMANDLINE_MODE_UNKNOWN:
- ++metric_setup_process_wait_failed_unknown;
- break;
- case COMMANDLINE_MODE_CORE:
- ++metric_setup_process_wait_failed_core;
- break;
- case COMMANDLINE_MODE_REPORTCRASH:
- ++metric_setup_process_wait_failed_report;
- break;
- case COMMANDLINE_MODE_UPDATE:
- ++metric_setup_process_wait_failed_update;
- break;
- case COMMANDLINE_MODE_HANDOFF_INSTALL:
- ++metric_setup_process_wait_failed_handoff;
- break;
- case COMMANDLINE_MODE_UA:
- ++metric_setup_process_wait_failed_ua;
- break;
- case COMMANDLINE_MODE_CODE_RED_CHECK:
- ++metric_setup_process_wait_failed_cr;
- break;
- case COMMANDLINE_MODE_NOARGS:
- case COMMANDLINE_MODE_SERVICE:
-
- case COMMANDLINE_MODE_REGSERVER:
- case COMMANDLINE_MODE_UNREGSERVER:
- case COMMANDLINE_MODE_NETDIAGS:
- case COMMANDLINE_MODE_CRASH:
- case COMMANDLINE_MODE_INSTALL:
- case COMMANDLINE_MODE_RECOVER:
- case COMMANDLINE_MODE_WEBPLUGIN:
- case COMMANDLINE_MODE_COMSERVER:
- case COMMANDLINE_MODE_REGISTER_PRODUCT:
- case COMMANDLINE_MODE_UNREGISTER_PRODUCT:
- case COMMANDLINE_MODE_SERVICE_REGISTER:
- case COMMANDLINE_MODE_SERVICE_UNREGISTER:
- case COMMANDLINE_MODE_CRASH_HANDLER:
- case COMMANDLINE_MODE_COMBROKER:
- case COMMANDLINE_MODE_ONDEMAND:
- case COMMANDLINE_MODE_MEDIUM_SERVICE:
- case COMMANDLINE_MODE_UNINSTALL:
- case COMMANDLINE_MODE_PING:
- default:
- ++metric_setup_process_wait_failed_other;
- break;
- }
-}
-
-// Returns the pids of all other GoogleUpdate.exe processes with the specified
-// argument string. Checks processes for all users that it has privileges to
-// access.
-HRESULT GetPidsWithArgsForAllUsers(const CString& args,
- std::vector<uint32>* pids) {
- ASSERT1(pids);
-
- std::vector<CString> command_line;
- command_line.push_back(args);
-
- DWORD flags = EXCLUDE_CURRENT_PROCESS |
- INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
- HRESULT hr = Process::FindProcesses(flags,
- kOmahaShellFileName,
- true,
- CString(),
- command_line,
- pids);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- return S_OK;
-}
-
-void WriteGoogleUpdateUninstallEvent(bool is_machine) {
- CString description;
- description.Format(kUninstallEventDescriptionFormat, kAppName);
- GoogleUpdateLogEvent uninstall_event(EVENTLOG_INFORMATION_TYPE,
- kUninstallEventId,
- is_machine);
- uninstall_event.set_event_desc(description);
- uninstall_event.WriteEvent();
-}
-
-// TODO(omaha3): Enable. Will we still need this method?
-// Returns true if the mode can be determined and pid represents a "/c" process.
-bool IsCoreProcess(uint32 pid) {
- CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
- return SUCCEEDED(GetProcessModeFromPid(pid, &mode)) &&
- COMMANDLINE_MODE_CORE == mode;
-}
-
-} // namespace
-
-bool Setup::did_uninstall_ = false;
-
-Setup::Setup(bool is_machine)
- : is_machine_(is_machine),
- is_self_update_(false),
- extra_code1_(S_OK) {
- SETUP_LOG(L2, (_T("[Setup::Setup]")));
-}
-
-Setup::~Setup() {
- SETUP_LOG(L2, (_T("[Setup::~Setup]")));
-}
-
-// Protects all setup-related operations with:
-// * Setup Lock - Prevents other instances from installing Google Update for
-// this machine/user at the same time.
-// * Shutdown Event - Tells existing other instances and any instances that may
-// start during Setup to exit.
-// Setup-related operations do not include installation of the app.
-HRESULT Setup::Install(bool set_keepalive) {
- SETUP_LOG(L3,
- (_T("[Admin=%d, NEAdmin=%d, Update3Svc=%d, MedSvc=%d, Machine=%d"),
- vista_util::IsUserAdmin(),
- vista_util::IsUserNonElevatedAdmin(),
- SetupUpdate3Service::IsServiceInstalled(),
- SetupUpdateMediumService::IsServiceInstalled(),
- is_machine_));
-
- ASSERT1(!IsElevationRequired());
-
- // Start the setup timer.
- metrics_timer_.reset(new HighresTimer);
-
- GLock setup_lock;
-
- if (!InitSetupLock(is_machine_, &setup_lock)) {
- SETUP_LOG(L2, (_T("[Setup::InitSetupLock failed]")));
- extra_code1_ = kVersion12;
- return GOOPDATE_E_SETUP_LOCK_INIT_FAILED;
- }
-
- HighresTimer lock_metrics_timer;
-
- if (!setup_lock.Lock(kSetupLockWaitMs)) {
- OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
- return HandleLockFailed(kVersion12);
- }
- metric_setup_lock_acquire_ms.AddSample(lock_metrics_timer.GetElapsedMs());
- SETUP_LOG(L1, (_T("[Setup Locks acquired]")));
-
- HRESULT hr = DoProtectedInstall(set_keepalive);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[Setup::DoProtectedInstall failed][0x%08x]"), hr));
- }
-
- SETUP_LOG(L1, (_T("[Releasing Setup Lock]")));
- return hr;
-}
-
-// TODO(omaha3): Eliminate lock_version if we do not fix http://b/1076207.
-// Sets appropriate metrics and extra_code1_ value. It then tries to determine
-// the scenario that caused this failure and returns an appropriate error.
-// The detected processes may not actually be in conflict with this one, but are
-// more than likely the cause of the lock failure.
-HRESULT Setup::HandleLockFailed(int lock_version) {
- ++metric_setup_locks_failed;
-
- switch (lock_version) {
- case kVersion12:
- extra_code1_ = kVersion12;
- ++metric_setup_lock12_failed;
- break;
- default:
- ASSERT1(false);
- extra_code1_ = -1;
- break;
- }
-
- Pids matching_pids;
- CString switch_to_include;
-
- switch_to_include.Format(_T("/%s"), kCmdLineUpdate);
- HRESULT hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
- if (FAILED(hr)) {
- ASSERT1(false);
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
- if (!matching_pids.empty()) {
- return GOOPDATE_E_FAILED_TO_GET_LOCK_UPDATE_PROCESS_RUNNING;
- }
-
- switch_to_include.Format(_T("/%s"), kCmdLineUninstall);
- hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
- if (FAILED(hr)) {
- ASSERT1(false);
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
- if (!matching_pids.empty()) {
- return GOOPDATE_E_FAILED_TO_GET_LOCK_UNINSTALL_PROCESS_RUNNING;
- }
-
- switch_to_include.Format(_T("/%s"), kCmdLineInstall);
- hr = GetPidsWithArgsForAllUsers(switch_to_include, &matching_pids);
- if (FAILED(hr)) {
- ASSERT1(false);
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
- if (matching_pids.empty()) {
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
-
- // Another /install process was found. Determine if it has the same cmd line.
- const TCHAR* this_cmd_line = ::GetCommandLine();
- if (!this_cmd_line) {
- ASSERT1(false);
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
- const CString current_cmd_line(this_cmd_line);
- if (current_cmd_line.IsEmpty()) {
- ASSERT1(false);
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
-
- // Strip the directory path, which may vary, and executable name.
- int exe_index = current_cmd_line.Find(kOmahaShellFileName);
- if (-1 == exe_index) {
- ASSERT(false, (_T("Unable to find %s in %s"),
- kOmahaShellFileName, current_cmd_line));
- return GOOPDATE_E_FAILED_TO_GET_LOCK;
- }
- int args_start = exe_index + _tcslen(kOmahaShellFileName);
- // Support enclosed paths; increment past closing double quote.
- if (_T('"') == current_cmd_line.GetAt(args_start)) {
- ++args_start;
- }
- const int args_length = current_cmd_line.GetLength() - args_start;
- CString current_args = current_cmd_line.Right(args_length);
- current_args.Trim();
-
- for (size_t i = 0; i < matching_pids.size(); ++i) {
- CString matching_pid_cmd_line;
- if (FAILED(Process::GetCommandLine(matching_pids[i],
- &matching_pid_cmd_line))) {
- continue;
- }
-
- if (-1 != matching_pid_cmd_line.Find(current_args)) {
- // Assume that this is a match and not a subset.
- return GOOPDATE_E_FAILED_TO_GET_LOCK_MATCHING_INSTALL_PROCESS_RUNNING;
- }
- }
-
- return GOOPDATE_E_FAILED_TO_GET_LOCK_NONMATCHING_INSTALL_PROCESS_RUNNING;
-}
-
-// Assumes the necessary locks have been acquired.
-HRESULT Setup::DoProtectedInstall(bool set_keepalive) {
- SETUP_LOG(L2, (_T("[Setup::DoProtectedInstall]")));
-
- SetupFiles setup_files(is_machine_);
-
- HRESULT hr = setup_files.Init();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[SetupFiles::Init failed][0x%08x]"), hr));
- return hr;
- }
-
- if (ShouldInstall(&setup_files)) {
- ++metric_setup_do_self_install_total;
-
- // TODO(omaha3): IMPORTANT: Try to avoid losing users due to firewall
- // blocking caused by changing the constant shell. Try a simple ping using
- // the new shell, and if it fails take one of the following actions:
- // 1) Keep the old shell (if possible).
- // 2) Fail the self-update. Leave the user on this version. Would need to
- // figure out a way to avoid updating the user every 5 hours.
-
- HRESULT hr = DoProtectedGoogleUpdateInstall(&setup_files);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[DoProtectedGoogleUpdateInstall fail][0x%08x]"), hr));
- // Do not return until rolling back and releasing the events.
- }
-
- if (FAILED(hr)) {
- RollBack(&setup_files);
- }
-
- // We need to hold the shutdown events until phase 2 is complete.
- // Phase 2 will release the current version's event. Here we release all
- // shutdown events, including the one that should have already been released
- // to be safe (i.e. in case phase 2 crashes).
- // This will happen before the Setup Lock is released, preventing any races.
- ReleaseShutdownEvents();
-
- if (FAILED(hr)) {
- return hr;
- }
-
- // If we've been asked to defer uninstall (typically because we're doing
- // an Omaha-only install to expose the COM API to a later process), set
- // it on a successful install.
- if (set_keepalive) {
- SetDelayUninstall(true);
- }
-
- ++metric_setup_do_self_install_succeeded;
- }
-
- return S_OK;
-}
-
-// Assumes that the shell is the correct version for the existing Omaha version.
-bool Setup::ShouldInstall(SetupFiles* setup_files) {
- SETUP_LOG(L2, (_T("[Setup::ShouldInstall]")));
- ASSERT1(setup_files);
-
- // TODO(omaha3): Figure out a different way to record these stats.
- bool is_install = true;
-
- ++metric_setup_should_install_total;
-
- ULONGLONG my_version = GetVersion();
-
- const ConfigManager* cm = ConfigManager::Instance();
- CString existing_version;
- HRESULT hr = RegKey::GetValue(cm->registry_clients_goopdate(is_machine_),
- kRegValueProductVersion,
- &existing_version);
- if (FAILED(hr)) {
- OPT_LOG(L2, (_T("[fresh install]")));
- ++metric_setup_should_install_true_fresh_install;
- return true;
- }
-
- OPT_LOG(L2, (_T("[Existing version: %s][Running version: %s]"),
- existing_version, GetVersionString()));
-
- // If running from the official install directory for this type of install
- // (user/machine), it is most likely a OneClick install. Do not install self.
- if (goopdate_utils::IsRunningFromOfficialGoopdateDir(is_machine_)) {
- ++metric_setup_should_install_false_oc;
- return false;
- }
-
- if (is_install) {
- ++metric_setup_subsequent_install_total;
- }
-
- bool should_install(false);
-
- ULONGLONG cv = VersionFromString(existing_version);
- if (cv > my_version) {
- SETUP_LOG(L2, (_T("[not installing, newer version exists]")));
- ++metric_setup_should_install_false_older;
- should_install = false;
- } else if (cv < my_version) {
- SETUP_LOG(L2, (_T("[installing with local build]")));
- ++metric_setup_should_install_true_newer;
- should_install = true;
- } else {
- // Same version.
- should_install = ShouldOverinstallSameVersion(setup_files);
- if (should_install) {
- ++metric_setup_should_install_true_same;
- } else {
- ++metric_setup_should_install_false_same;
- }
- }
-
- if (is_install && should_install) {
- ++metric_setup_subsequent_install_should_install_true;
- }
-
- OPT_LOG(L1, (_T("[machine = %d][existing version = %s][should_install = %d]"),
- is_machine_, existing_version, should_install));
-
- return should_install;
-}
-
-// Checks the following:
-// * OverInstall override.
-// * The "installed" version in the registry equals this version.
-// If not, this version was not fully installed even though "pv" says it is.
-// * Files are properly installed.
-bool Setup::ShouldOverinstallSameVersion(SetupFiles* setup_files) {
- SETUP_LOG(L2, (_T("[Setup::ShouldOverinstallSameVersion]")));
- ASSERT1(setup_files);
-
- const ConfigManager* cm = ConfigManager::Instance();
-
- bool should_over_install = cm->CanOverInstall();
- SETUP_LOG(L1, (_T("[should over install = %d]"), should_over_install));
- if (should_over_install) {
- SETUP_LOG(L2, (_T("[overinstalling with local build]")));
- return true;
- }
-
- CString installed_version;
- HRESULT hr = RegKey::GetValue(cm->registry_update(is_machine_),
- kRegValueInstalledVersion,
- &installed_version);
- if (FAILED(hr) || GetVersionString() != installed_version) {
- SETUP_LOG(L1, (_T("[installed version missing or did not match][%s]"),
- installed_version));
- ++metric_setup_should_install_true_same_completion_missing;
- return true;
- }
-
- if (setup_files->ShouldOverinstallSameVersion()) {
- SETUP_LOG(L1, (_T("[files need over-install]")));
- return true;
- }
-
- // TODO(omaha): Verify the current installation is complete and correct.
- // For example, in Omaha 1, we would always set the run key to the version
- // being installed. Now that code is in SetupGoogleUpdate, and it does not get
- // called.
-
- return false;
-}
-
-HRESULT Setup::DoProtectedGoogleUpdateInstall(SetupFiles* setup_files) {
- ASSERT1(setup_files);
- SETUP_LOG(L2, (_T("[Setup::DoProtectedGoogleUpdateInstall]")));
-
- HRESULT hr = StopGoogleUpdateAndWait();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[StopGoogleUpdateAndWait failed][0x%08x]"), hr));
- if (E_ACCESSDENIED == hr) {
- return GOOPDATE_E_ACCESSDENIED_STOP_PROCESSES;
- }
- return hr;
- }
-
-// TODO(omaha3): Enable. Prefer to move out of Setup if possible.
-#if 0
- VERIFY1(SUCCEEDED(ResetMetrics(is_machine_)));
-#endif
-
- hr = RegKey::GetValue(
- ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
- kRegValueProductVersion,
- &saved_version_);
- if (FAILED(hr)) {
- SETUP_LOG(L3, (_T("[failed to get existing Omaha version][0x%08x]"), hr));
- // Continue as this is expected for first installs.
- }
-
- hr = setup_files->Install();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[SetupFiles::Install failed][0x%08x]"), hr));
- extra_code1_ =
- setup_files->extra_code1() | PingEvent::kSetupFilesExtraCodeMask;
- return hr;
- }
-
- hr = SetupGoogleUpdate();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[SetupGoogleUpdate failed][0x%08x]"), hr));
- return hr;
- }
-
- // TODO(omaha3): Maybe move out of Setup.
- metric_setup_install_google_update_total_ms.AddSample(
- metrics_timer_->GetElapsedMs());
-
- return S_OK;
-}
-
-void Setup::RollBack(SetupFiles* setup_files) {
- OPT_LOG(L1, (_T("[Roll back]")));
- ASSERT1(setup_files);
-
- // Restore the saved version.
- if (!saved_version_.IsEmpty()) {
- SETUP_LOG(L1, (_T("[Rolling back version to %s]"), saved_version_));
- ++metric_setup_rollback_version;
-
- VERIFY1(SUCCEEDED(RegKey::SetValue(
- ConfigManager::Instance()->registry_clients_goopdate(is_machine_),
- kRegValueProductVersion,
- saved_version_)));
- }
-
- // TODO(omaha3): Rollback SetupGoogleUpdate.
- VERIFY1(SUCCEEDED(setup_files->RollBack()));
-}
-
-// Assumes the caller is ensuring this is the only running instance of setup.
-// The original process holds the lock while it waits for this one to complete.
-HRESULT Setup::SetupGoogleUpdate() {
- SETUP_LOG(L2, (_T("[Setup::SetupGoogleUpdate]")));
-
- HighresTimer phase2_metrics_timer;
-
- omaha::SetupGoogleUpdate setup_google_update(is_machine_);
-
- HRESULT hr = setup_google_update.FinishInstall();
- if (FAILED(hr)) {
- extra_code1_ = setup_google_update.extra_code1();
- SETUP_LOG(LE, (_T("[FinishInstall failed][0x%x][0x%x]"), hr, extra_code1_));
- return hr;
- }
-
- // Release the shutdown event so that we can start the core if necessary, and
- // we do not interfere with other app installs that may be waiting on the
- // Setup Lock.
- ASSERT1(shutdown_event_);
- ReleaseShutdownEvents();
-
- if (!scheduled_task_utils::IsUATaskHealthy(is_machine_)) {
- HRESULT start_hr = StartCore();
- if (FAILED(start_hr)) {
- SETUP_LOG(LW, (_T("[StartCore failed][0x%x]"), start_hr));
- }
- }
-
- // Registration of browser plugins is only done after the shutdown event has
- // been released; this prevents race conditions where a browser could start
- // a new install while the shutdown event was still being held.
- HRESULT plugin_hr = setup_google_update.InstallBrowserPlugins();
- if (FAILED(plugin_hr)) {
- SETUP_LOG(LE, (_T("[InstallBrowserPlugins failed][0x%08x]"), plugin_hr));
- }
-
- // Setup is now complete.
-
- metric_setup_phase2_ms.AddSample(phase2_metrics_timer.GetElapsedMs());
- return S_OK;
-}
-
-// Stops all user/machine instances including the service, unregisters using
-// SetupGoogleUpdate, then deletes the files using SetupFiles.
-// Does not wait for the processes to exit, except the service.
-// Protects all operations with the setup lock. If MSI is found busy, Omaha
-// won't uninstall.
-HRESULT Setup::Uninstall(bool send_uninstall_ping) {
- OPT_LOG(L1, (_T("[Setup::Uninstall]")));
- ASSERT1(!IsElevationRequired());
-
- // Try to get the global setup lock; if the lock is taken, do not block
- // waiting to uninstall; just return.
- GLock setup_lock;
- VERIFY1(InitSetupLock(is_machine_, &setup_lock));
- if (!setup_lock.Lock(0)) {
- OPT_LOG(LE, (_T("[Failed to acquire setup lock]")));
- return E_FAIL;
- }
-
- return DoProtectedUninstall(send_uninstall_ping);
-}
-
-// Aggregates metrics regardless of whether uninstall is allowed.
-// Foces reporting of the metrics if uninstall is allowed.
-// Assumes that the current process holds the Setup Lock.
-HRESULT Setup::DoProtectedUninstall(bool send_uninstall_ping) {
- const bool can_uninstall = CanUninstallGoogleUpdate();
- OPT_LOG(L1, (_T("[CanUninstallGoogleUpdate returned %d]"), can_uninstall));
-
- HRESULT hr = S_OK;
- if (!can_uninstall) {
- hr = GOOPDATE_E_CANT_UNINSTALL;
- } else {
- hr = StopGoogleUpdateAndWait();
- if (FAILED(hr)) {
- // If there are any clients that don't listen to the shutdown event,
- // such as the current Update3Web workers, we'll need to wait until
- // they can be shut down.
- // TODO(omaha3): We might want to add a count metric for this case,
- // and maybe go through with the uninstall anyways after several tries.
- SETUP_LOG(L1, (_T("[StopGoogleUpdateAndWait returned 0x%08x]"), hr));
- hr = GOOPDATE_E_CANT_UNINSTALL;
- }
- }
-
- if (FAILED(hr)) {
- VERIFY1(SUCCEEDED(AggregateMetrics(is_machine_)));
- return hr;
- }
- hr = AggregateAndReportMetrics(is_machine_, true);
- ASSERT1(SUCCEEDED(hr) || GOOPDATE_E_CANNOT_USE_NETWORK == hr);
-
- bool can_use_network = ConfigManager::Instance()->CanUseNetwork(is_machine_);
- if (can_use_network && send_uninstall_ping) {
- SendUninstallPing();
- }
-
- // Write the event in the event log before uninstalling the program since
- // the event contains version and language information, which are removed
- // during the uninstall.
- WriteGoogleUpdateUninstallEvent(is_machine_);
-
- omaha::SetupGoogleUpdate setup_google_update(is_machine_);
- setup_google_update.Uninstall();
-
- SetupFiles setup_files(is_machine_);
- setup_files.Uninstall();
-
- OPT_LOG(L1, (_T("[Uninstall complete]")));
- did_uninstall_ = true;
- return S_OK;
-}
-
-// Should only be called after the point where Uninstall would have been called.
-// Works correctly in the case where the Setup Lock is not held but an app is
-// being installed because it does not check the number of registered apps.
-// Either Omaha is installed or has been cleaned up.
-// Installed means Clients, ClientState, etc. sub keys exist.
-// Cleaned up may mean the Update key does not exist or some values, such as
-// mid and uid exist, but there are no subkeys.
-// The Update key should never exist without any values.
-// Does not take the Setup Lock because it is just a dbg check. It is possible
-// for the value of did_uninstall_ to be changed in another thread or for
-// another process to install or uninstall Google Update while this is running.
-void Setup::CheckInstallStateConsistency(bool is_machine) {
- UNREFERENCED_PARAMETER(is_machine);
-#if DEBUG
- CString key_name = ConfigManager::Instance()->registry_update(is_machine);
- if (!RegKey::HasKey(key_name)) {
- // Either this instance called uninstall or it is the non-elevated machine
- // instance on Vista and later. Both cannot be true in the same instance.
- ASSERT1(did_uninstall_ != (is_machine && !vista_util::IsUserAdmin()));
- return;
- }
-
- RegKey update_key;
- ASSERT1(SUCCEEDED(update_key.Open(key_name, KEY_READ)));
-
- ASSERT1(0 != update_key.GetValueCount());
-
- if (did_uninstall_) {
- ASSERT1(0 == update_key.GetSubkeyCount());
- ASSERT1(!update_key.HasValue(kRegValueInstalledVersion));
- ASSERT1(!update_key.HasValue(kRegValueInstalledPath));
- } else {
- ASSERT1(update_key.HasSubkey(_T("Clients")));
- ASSERT1(update_key.HasSubkey(_T("ClientState")));
- ASSERT1(update_key.HasSubkey(_T("network")));
- ASSERT1(update_key.HasValue(kRegValueInstalledVersion));
- ASSERT1(update_key.HasValue(kRegValueInstalledPath));
-
- CString installed_version;
- ASSERT1(SUCCEEDED(update_key.GetValue(kRegValueInstalledVersion,
- &installed_version)));
- const CString state_key_name =
- ConfigManager::Instance()->registry_client_state_goopdate(is_machine);
- CString pv;
- ASSERT1(SUCCEEDED(RegKey::GetValue(state_key_name,
- kRegValueProductVersion,
- &pv)));
- ASSERT1(installed_version == pv);
- }
-#endif
-}
-
-// Stops both legacy and current instances.
-// Holds the shutdown events so that other instances do not start running.
-// The caller is responsible for releasing the events.
-// Because this waiting occurs before a UI is generated, we do not want to wait
-// too long.
-HRESULT Setup::StopGoogleUpdate() {
- OPT_LOG(L1, (_T("[Stopping other instances]")));
-
- HRESULT hr = SignalShutdownEvent();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[SignalShutdownEvent failed][0x%08x]"), hr));
- return hr;
- }
-
- return S_OK;
-}
-
-HRESULT Setup::StopGoogleUpdateAndWait() {
- HRESULT hr = StopGoogleUpdate();
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[StopGoogleUpdate failed][0x%08x]"), hr));
- return hr;
- }
-
- Pids pids;
- hr = GetPidsToWaitFor(&pids);
- if (FAILED(hr)) {
- SETUP_LOG(LEVEL_ERROR, (_T("[GetPidsToWaitFor failed][0x%08x]"), hr));
- return hr;
- }
-
- hr = WaitForOtherInstancesToExit(pids);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[WaitForOtherInstancesToExit failed][0x%08x]"), hr));
- return hr;
- }
-
- return S_OK;
-}
-
-// Signals >= 1.2.x processes to exit.
-HRESULT Setup::SignalShutdownEvent() {
- SETUP_LOG(L1, (_T("[Setup::SignalShutdownEvent]")));
- NamedObjectAttributes event_attr;
- GetShutdownEventAttributes(is_machine_, &event_attr);
-
- if (!shutdown_event_) {
- HRESULT hr = goopdate_utils::CreateEvent(&event_attr,
- address(shutdown_event_));
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[CreateEvent current failed][0x%08x]"), hr));
- return hr;
- }
- }
-
- VERIFY1(::SetEvent(get(shutdown_event_)));
-
- return S_OK;
-}
-
-void Setup::ReleaseShutdownEvents() {
- if (!shutdown_event_) {
- return;
- }
-
- VERIFY1(::ResetEvent(get(shutdown_event_)));
- reset(shutdown_event_);
-}
-
-// Because this waiting can occur before a UI is generated, we do not want to
-// wait too long.
-// If a process fails to stop, its mode is stored in extra_code1_.
-// Does not return until all opened handles have been closed.
-// TODO(omaha): Add a parameter to specify the amount of time to wait to this
-// method and StopGoogleUpdateAndWait after we unify Setup and always have a UI.
-HRESULT Setup::WaitForOtherInstancesToExit(const Pids& pids) {
- OPT_LOG(L1, (_T("[Waiting for other instances to exit]")));
-
- // Wait for all the processes to exit.
- std::vector<HANDLE> handles;
- for (size_t i = 0; i < pids.size(); ++i) {
- SETUP_LOG(L2, (_T("[Waiting for process][%u]"), pids[i]));
-
- DWORD desired_access =
- PROCESS_QUERY_INFORMATION | SYNCHRONIZE | PROCESS_TERMINATE;
- scoped_handle handle(::OpenProcess(desired_access,
- FALSE,
- pids[i]));
- if (!handle) {
- HRESULT hr = HRESULTFromLastError();
- SETUP_LOG(LE, (_T("[::OpenProcess failed][%u][0x%08x]"), pids[i], hr));
- continue;
- }
-
- handles.push_back(release(handle));
- }
-
- HRESULT hr = S_OK;
- if (!handles.empty()) {
- SETUP_LOG(L2, (_T("[Calling ::WaitForMultipleObjects]")));
-
- HighresTimer metrics_timer;
- const int wait_ms = is_self_update_ ? kSetupUpdateShutdownWaitMs :
- kSetupInstallShutdownWaitMs;
- DWORD res = ::WaitForMultipleObjects(handles.size(),
- &handles.front(),
- true, // wait for all
- wait_ms);
- metric_setup_process_wait_ms.AddSample(metrics_timer.GetElapsedMs());
-
- SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
- ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
- if (WAIT_FAILED == res) {
- const DWORD error = ::GetLastError();
- SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
- hr = HRESULT_FROM_WIN32(error);
- } else if (WAIT_OBJECT_0 != res) {
- OPT_LOG(LEVEL_ERROR, (_T("[Other GoogleUpdate.exe instances failed to ")
- _T("shutdown in time][%u]"), res));
-
- extra_code1_ = COMMANDLINE_MODE_UNKNOWN;
-
- SETUP_LOG(L2, (_T("[Listing processes that did not exit. This may be ")
- _T("incomplete if processes exited after ")
- _T("WaitForMultipleObjects returned.]")));
- for (size_t i = 0; i < handles.size(); ++i) {
- if (WAIT_TIMEOUT == ::WaitForSingleObject(handles[i], 0)) {
- uint32 pid = Process::GetProcessIdFromHandle(handles[i]);
- if (!pid) {
- SETUP_LOG(LW, (_T(" [Process::GetProcessIdFromHandle failed][%u]"),
- ::GetLastError()));
- SETUP_LOG(L2, (_T(" [Process did not exit][unknown]")));
- continue;
- }
- SETUP_LOG(L2, (_T(" [Process did not exit][%u]"), pid));
-
- CommandLineMode mode(COMMANDLINE_MODE_UNKNOWN);
- if (SUCCEEDED(GetProcessModeFromPid(pid, &mode))) {
- extra_code1_ = mode;
- }
- IncrementProcessWaitFailCount(mode);
- }
- }
-
- ++metric_setup_process_wait_failed;
- hr = GOOPDATE_E_INSTANCES_RUNNING;
- }
- }
- if (SUCCEEDED(hr)) {
- SETUP_LOG(L3, (_T("[Wait for all processes to exit succeeded]")));
- } else {
- for (size_t i = 0; i < handles.size(); ++i) {
- if (!::TerminateProcess(handles[i], UINT_MAX)) {
- const uint32 pid = Process::GetProcessIdFromHandle(handles[i]);
- const DWORD error = ::GetLastError();
- SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"), pid, error));
- }
- }
-
- const int kTerminateWaitMs = 500;
- DWORD res = ::WaitForMultipleObjects(handles.size(), &handles.front(),
- true, kTerminateWaitMs);
- if (res != WAIT_OBJECT_0) {
- const DWORD error = ::GetLastError();
- SETUP_LOG(LW, (_T("[Wait failed][%u][%u]"), res, error));
- }
- }
-
- // Close the handles.
- for (size_t i = 0; i < handles.size(); ++i) {
- if (!::CloseHandle(handles[i])) {
- HRESULT hr = HRESULTFromLastError();
- SETUP_LOG(LEVEL_WARNING, (_T("[CloseHandle failed][0x%08x]"), hr));
- }
- }
-
- return S_OK;
-}
-
-// Wait for all instances of Omaha running as the current user - or as any user
-// in the case of machine installs - except "/install" or "/registerproduct"
-// instances, which should be blocked by the Setup Lock, which we are holding.
-HRESULT Setup::GetPidsToWaitFor(Pids* pids) const {
- ASSERT1(pids);
-
- HRESULT hr = GetPidsToWaitForUsingCommandLine(pids);
- if (FAILED(hr)) {
- return hr;
- }
-
- ASSERT1(pids->end() == std::find(pids->begin(), pids->end(),
- ::GetCurrentProcessId()));
- SETUP_LOG(L3, (_T("[found %d total processes to wait for]"), pids->size()));
-
- return S_OK;
-}
-
-// Finds processes to wait for based on the command line.
-// Differences between Omaha 2 and this code:
-// * User's processes running outside AppData are not caught. This should only
-// be /install or /registerproduct.
-// * In the user case, "machine" processes running as the user are EXcluded
-// based on path instead of mode and "needsadmin=true". This additionally
-// excludes oneclick cross-installs (u-to-m).
-// * In the machine case, "machine" processes running as the user are INcluded
-// based on path instead of mode and "needsadmin=true".
-// * /pi: m-to-u running in PF as user with needsadmin=false: now INcluded.
-// This is a good idea, since we do not want to delete the in-use file.
-// /pi: u-to-m running in appdata as user with needsadmin=true: now
-// EXcluded.
-HRESULT Setup::GetPidsToWaitForUsingCommandLine(Pids* pids) const {
- CORE_LOG(L3, (_T("[Setup::GetPidsToWaitForUsingCommandLine]")));
-
- ASSERT1(pids);
-
- // Get processes running as the current user in the case of user, and all
- // users as well as SYSTEM in the case of machine, except those with
- // * "/install" - must be excluded because may be waiting for the Setup Lock.
- // * "/registerproduct" - same as for /install.
- std::vector<CString> command_lines;
- CString switch_to_exclude;
- switch_to_exclude.Format(_T("/%s"), kCmdLineInstall);
- command_lines.push_back(switch_to_exclude);
- switch_to_exclude.Format(_T("/%s"), kCmdLineRegisterProduct);
-
- CString user_sid;
- DWORD flags = EXCLUDE_CURRENT_PROCESS |
- EXCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
-
- if (!is_machine_) {
- // Search only the same sid as the current user.
- flags |= INCLUDE_ONLY_PROCESS_OWNED_BY_USER;
-
- HRESULT hr = user_info::GetProcessUser(NULL, NULL, &user_sid);
- if (FAILED(hr)) {
- CORE_LOG(LE, (_T("[GetProcessUser failed][0x%x]"), hr));
- return hr;
- }
- }
-
- std::vector<uint32> google_update_process_ids;
- HRESULT hr = Process::FindProcesses(flags,
- kOmahaShellFileName,
- true,
- user_sid,
- command_lines,
- &google_update_process_ids);
- if (FAILED(hr)) {
- CORE_LOG(LE, (_T(" [FindProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- const ConfigManager* cm = ConfigManager::Instance();
- CString official_path(is_machine_ ?
- cm->GetMachineGoopdateInstallDirNoCreate() :
- cm->GetUserGoopdateInstallDirNoCreate());
- ASSERT1(!official_path.IsEmpty());
-
- // Only include processes running under the official path.
- Pids pids_to_wait_for;
- for (size_t i = 0; i < google_update_process_ids.size(); ++i) {
- CString cmd_line;
- const uint32 process_id = google_update_process_ids[i];
- if (SUCCEEDED(Process::GetCommandLine(process_id, &cmd_line))) {
- cmd_line.MakeLower();
-
- CString exe_path;
- if (SUCCEEDED(GetExePathFromCommandLine(cmd_line, &exe_path)) &&
- String_StrNCmp(official_path, exe_path, official_path.GetLength(),
- true) == 0) {
- CORE_LOG(L4, (_T(" [Including pid][%u][%s]"), process_id, cmd_line));
- pids_to_wait_for.push_back(process_id);
- }
- }
- }
-
- pids->swap(pids_to_wait_for);
- return S_OK;
-}
-
-// On Windows Vista, an admin must be elevated in order to install a machine app
-// without elevating. On Vista, IsUserAdmin returns false unless the user is
-// elevated.
-bool Setup::IsElevationRequired() const {
- return is_machine_ && !vista_util::IsUserAdmin();
-}
-
-// Start the machine core process using one of the launch mechanisms.
-// We know that at least one of the service and scheduled task were installed
-// because otherwise we would have exited fatally.
-// If the service was not installed, starting it will just fail silently and we
-// will start the scheduled task.
-// do not call this method until the shutdown event has been released or the
-// process may immediately exit.
-// TODO(omaha): Provide service_hr and task_hr failures in a ping.
-HRESULT Setup::StartMachineCoreProcess() const {
- SETUP_LOG(L3, (_T("[Setup::StartMachineCoreProcess]")));
-
- HighresTimer metrics_timer;
-
- // Start the service.
- ++metric_setup_start_service_total;
- HRESULT service_hr = SetupUpdate3Service::StartService();
- if (SUCCEEDED(service_hr)) {
- metric_setup_start_service_ms.AddSample(metrics_timer.GetElapsedMs());
- OPT_LOG(L1, (_T("[Service started]")));
- ++metric_setup_start_service_succeeded;
- return S_OK;
- }
- metric_setup_start_service_failed_ms.AddSample(metrics_timer.GetElapsedMs());
- OPT_LOG(LEVEL_ERROR, (_T("[Start service failed][0x%08x]"), service_hr));
- metric_setup_start_service_error = service_hr;
-
- // TODO(omaha): We should only skip this block when /install /silent fails
- // and there are no other apps installed. Guarantee this somehow.
- ++metric_setup_start_task_total;
- const ULONGLONG start_task_start_ms = metrics_timer.GetElapsedMs();
- HRESULT task_hr = scheduled_task_utils::StartGoopdateTaskCore(true);
- if (SUCCEEDED(task_hr)) {
- const ULONGLONG start_task_end_ms = metrics_timer.GetElapsedMs();
- ASSERT1(start_task_end_ms >= start_task_start_ms);
- metric_setup_start_task_ms.AddSample(
- start_task_end_ms - start_task_start_ms);
- OPT_LOG(L1, (_T("[run scheduled task succeeded]")));
- ++metric_setup_start_task_succeeded;
- return S_OK;
- }
- OPT_LOG(LE, (_T("[Start scheduled task failed][0x%08x]"), task_hr));
- metric_setup_start_task_error = task_hr;
-
- return service_hr;
-}
-
-// Start the user core process directly.
-// Do not call this method until the shutdown event has been released or the
-// process may immediately exit.
-HRESULT Setup::StartUserCoreProcess(const CString& core_cmd_line) const {
- HRESULT hr = System::StartCommandLine(core_cmd_line);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[Could not start Google Update Core][0x%08x]"), hr));
- return hr;
- }
-
- return S_OK;
-}
-
-HRESULT Setup::FindCoreProcesses(Pids* found_core_pids) const {
- SETUP_LOG(L3, (_T("[Setup::FindCoreProcesses]")));
- ASSERT1(found_core_pids);
-
- CString user_sid;
- HRESULT hr = GetAppropriateSid(&user_sid);
- if (FAILED(hr)) {
- return hr;
- }
-
- std::vector<CString> command_lines;
- CString switch_to_include;
- switch_to_include.Format(_T("/%s"), kCmdLineCore);
- command_lines.push_back(switch_to_include);
-
- DWORD flags = INCLUDE_ONLY_PROCESS_OWNED_BY_USER |
- EXCLUDE_CURRENT_PROCESS |
- INCLUDE_PROCESS_COMMAND_LINE_CONTAINING_STRING;
- hr = Process::FindProcesses(flags,
- kOmahaShellFileName,
- true,
- user_sid,
- command_lines,
- found_core_pids);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[FindProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- // Remove PIDs where the command line is not actually the "/c" switch and is
- // some other command line, such as "/cr".
- const Pids::iterator new_end = std::remove_if(
- found_core_pids->begin(),
- found_core_pids->end(),
- std::not1(std::ptr_fun(IsCoreProcess)));
- if (new_end != found_core_pids->end()) {
- found_core_pids->erase(new_end, found_core_pids->end());
- }
-
- SETUP_LOG(L2, (_T("[Core processes found][%u]"), found_core_pids->size()));
- return S_OK;
-}
-
-// Does not try to terminate legacy processes.
-// Waits up to 500 ms for the terminated core processes to exit.
-HRESULT Setup::TerminateCoreProcesses() const {
- SETUP_LOG(L2, (_T("[Setup::TerminateCoreProcesses]")));
- Pids found_core_pids;
- HRESULT hr = FindCoreProcesses(&found_core_pids);
- if (FAILED(hr)) {
- SETUP_LOG(LE, (_T("[FindCoreProcesses failed][0x%08x]"), hr));
- return hr;
- }
-
- std::vector<HANDLE> terminated_processes;
- for (size_t i = 0; i < found_core_pids.size(); ++i) {
- uint32 pid = found_core_pids[i];
-
- SETUP_LOG(L2, (_T("[Terminating core process][%u]"), pid));
-
- HANDLE process(::OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, pid));
- if (!process) {
- SETUP_LOG(LW, (_T("[::OpenProcess failed][%u][%u]"),
- pid, ::GetLastError()));
- continue;
- }
- terminated_processes.push_back(process);
-
- if (!::TerminateProcess(process, static_cast<uint32>(-2))) {
- SETUP_LOG(LW, (_T("[::TerminateProcess failed][%u][%u]"),
- pid, ::GetLastError()));
- }
- }
-
- if (terminated_processes.empty()) {
- return S_OK;
- }
- // Do not return until the handles have been closed.
-
- const int kCoreTerminateWaitMs = 500;
- DWORD res = ::WaitForMultipleObjects(terminated_processes.size(),
- &terminated_processes.front(),
- true, // wait for all
- kCoreTerminateWaitMs);
- SETUP_LOG(L2, (_T("[::WaitForMultipleObjects returned]")));
- ASSERT1(WAIT_OBJECT_0 == res || WAIT_TIMEOUT == res);
- if (WAIT_FAILED == res) {
- const DWORD error = ::GetLastError();
- SETUP_LOG(LE, (_T("[::WaitForMultipleObjects failed][%u]"), error));
- hr = HRESULT_FROM_WIN32(error);
- } else {
- hr = HRESULT_FROM_WIN32(res);
- }
-
- for (size_t i = 0; i < terminated_processes.size(); ++i) {
- VERIFY1(::CloseHandle(terminated_processes[i]));
- }
-
- return hr;
-}
-
-// Tries to start the core using existing launch methods if present.
-// Uses the service or the scheduled task for machine, and the Run key value for
-// user.
-HRESULT Setup::StartCore() const {
- SETUP_LOG(L2, (_T("[Attempting to start core]")));
-
- if (is_machine_) {
- HRESULT hr = StartMachineCoreProcess();
- if (FAILED(hr)) {
- SETUP_LOG(LW, (_T("[StartMachineCoreProcess failed][0x%08x]"), hr));
- return hr;
- }
-
- return hr;
- }
-
- CString installed_run_cmd_line;
- HRESULT hr = RegKey::GetValue(USER_KEY REGSTR_PATH_RUN, kRunValueName,
- &installed_run_cmd_line);
- if (FAILED(hr)) {
- SETUP_LOG(LW, (_T("[Failed to get Run val][%s][0x%x]"), kRunValueName, hr));
- return hr;
- }
-
- hr = StartUserCoreProcess(installed_run_cmd_line);
- if (FAILED(hr)) {
- SETUP_LOG(LW, (_T("[StartUserCoreProcess failed][%s][0x%x]"),
- installed_run_cmd_line, hr));
- return hr;
- }
-
- return S_OK;
-}
-
-// Returns Local System's SID for machine installs and the user's SID otherwise.
-HRESULT Setup::GetAppropriateSid(CString* sid) const {
- ASSERT1(sid);
- if (is_machine_) {
- *sid = kLocalSystemSid;
- } else {
- HRESULT hr = user_info::GetProcessUser(NULL, NULL, sid);
- if (FAILED(hr)) {
- SETUP_LOG(LEVEL_ERROR, (_T("[GetProcessUser failed][0x%08x]"), hr));
- return hr;
- }
- }
-
- return S_OK;
-}
-
-bool Setup::InitSetupLock(bool is_machine, GLock* setup_lock) {
- ASSERT1(setup_lock);
- NamedObjectAttributes setup_lock_attr;
- GetNamedObjectAttributes(kSetupMutex, is_machine, &setup_lock_attr);
- return setup_lock->InitializeWithSecAttr(setup_lock_attr.name,
- &setup_lock_attr.sa);
-}
-
-// Assumes that the Setup Lock is held.
-// This method is based on the assumption that if another install, which could
-// be modifying the number of clients, is in progress, that it either:
-// (a) Has the Setup Lock, which is not possible because this process has it.
-// (b) Has started an install worker.
-// TODO(omaha3): This is flawed: http://b/2764048.
-bool Setup::CanUninstallGoogleUpdate() const {
- CORE_LOG(L2, (_T("[Setup::CanUninstallGoogleUpdate]")));
- if (goopdate_utils::IsAppInstallWorkerRunning(is_machine_)) {
- CORE_LOG(L2, (_T("[Found install workers. Not uninstalling]")));
- return false;
- }
- if (ShouldDelayUninstall()) {
- // If the DelayUninstall flag is set, that implies that someone has
- // installed us with the runtime=true flag, expecting that they can
- // use our API later from another process. If 24 hours have passed
- // since that initial Omaha install, we clear the flag but still
- // return false for this check. (That way, if a machine has been
- // suspended in mid-install, they still have a grace period until
- // the next /ua to get something installed.)
- CORE_LOG(L3, (_T("[DelayUninstall is set. Not uninstalling.]")));
- if (ConfigManager::Instance()->Is24HoursSinceInstall(is_machine_)) {
- CORE_LOG(L4, (_T("[24 hours elapsed; clearing DelayUninstall.]")));
- SetDelayUninstall(false);
- }
- return false;
- }
- size_t num_clients(0);
- if (SUCCEEDED(app_registry_utils::GetNumClients(is_machine_, &num_clients)) &&
- num_clients >= 2) {
- CORE_LOG(L3, (_T("[Found products. Not uninstalling]")));
- return false;
- }
-
- return true;
-}
-
-bool Setup::ShouldDelayUninstall() const {
- const TCHAR* key = ConfigManager::Instance()->registry_update(is_machine_);
- if (!RegKey::HasValue(key, kRegValueDelayOmahaUninstall)) {
- return false;
- }
- DWORD should_delay = 0;
- if (FAILED(RegKey::GetValue(key,
- kRegValueDelayOmahaUninstall,
- &should_delay))) {
- return false;
- }
- return should_delay != 0;
-}
-
-HRESULT Setup::SetDelayUninstall(bool should_delay) const {
- const TCHAR* key = ConfigManager::Instance()->registry_update(is_machine_);
- if (should_delay) {
- return RegKey::SetValue(key, kRegValueDelayOmahaUninstall, 1UL);
- } else {
- return RegKey::DeleteValue(key, kRegValueDelayOmahaUninstall);
- }
-}
-
-HRESULT Setup::SendUninstallPing() {
- CORE_LOG(L3, (_T("[SendUninstallPing]")));
-
- const bool is_eula_accepted =
- app_registry_utils::IsAppEulaAccepted(is_machine_,
- kGoogleUpdateAppId,
- false);
-
- if (!is_eula_accepted) {
- CORE_LOG(LE, (_T("[SendUninstallPing - eula not accepted]")));
- return E_FAIL;
- }
-
- PingEventPtr uninstall_ping_event(
- new PingEvent(PingEvent::EVENT_UNINSTALL,
- PingEvent::EVENT_RESULT_SUCCESS,
- 0,
- 0));
-
- // Generate a session ID for uninstall pings. NOTE: The assumption here is
- // that if /uninstall was launched by /ua, we have no updates to check for,
- // so we assume that /ua won't use its own session ID. If /ua does any
- // network activity on a no-clients case, we will have to start passing the
- // session ID from /ua to /uninstall in the future.
- CString session_id;
- VERIFY1(SUCCEEDED(GetGuid(&session_id)));
-
- // Send uninstall ping for uninstalled apps.
- HRESULT hr = S_OK;
- std::vector<CString> uninstalled_apps;
- if (SUCCEEDED(app_registry_utils::GetUninstalledApps(is_machine_,
- &uninstalled_apps))) {
- Ping apps_uninstall_ping(is_machine_, session_id, kInstallSource_Uninstall);
- apps_uninstall_ping.LoadAppDataFromRegistry(uninstalled_apps);
- apps_uninstall_ping.BuildAppsPing(uninstall_ping_event);
-
- hr = apps_uninstall_ping.Send(false);
- if (FAILED(hr)) {
- CORE_LOG(LE, (_T("[SendUninstallPing: failed to send app uninstall ping]")
- _T("[0x%08x]"), hr));
- }
- }
-
- // Send uninstall ping for Omaha.
- const CString current_omaha_version(GetVersionString());
- const CString next_omaha_version; // Empty, in the uninstall case.
- Ping omaha_uninstall_ping(is_machine_, session_id, kInstallSource_Uninstall);
- omaha_uninstall_ping.LoadOmahaDataFromRegistry();
- omaha_uninstall_ping.BuildOmahaPing(current_omaha_version,
- next_omaha_version,
- uninstall_ping_event);
- hr = omaha_uninstall_ping.Send(false);
- if (SUCCEEDED(hr)) {
- // Clears the registry after ping is sent successfully.
- std::vector<CString> uninstalled_apps;
- app_registry_utils::GetUninstalledApps(is_machine_, &uninstalled_apps);
- app_registry_utils::RemoveClientStateForApps(is_machine_, uninstalled_apps);
- } else {
- CORE_LOG(LE, (_T("[SendUninstallPing: failed to send Omaha uninstall ping]")
- _T("[0x%08x]"), hr));
- }
-
- return hr;
-}
-
-
-} // namespace omaha
« no previous file with comments | « setup/setup.h ('k') | setup/setup_files.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698