Index: goopdate/install_manager.cc |
diff --git a/goopdate/install_manager.cc b/goopdate/install_manager.cc |
deleted file mode 100644 |
index 9522f9801491c259ee7f612fe077cfd21709c44f..0000000000000000000000000000000000000000 |
--- a/goopdate/install_manager.cc |
+++ /dev/null |
@@ -1,361 +0,0 @@ |
-// Copyright 2009-2010 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. |
-// ======================================================================== |
- |
-#include "omaha/goopdate/install_manager.h" |
-#include <vector> |
-#include "omaha/base/debug.h" |
-#include "omaha/base/error.h" |
-#include "omaha/base/logging.h" |
-#include "omaha/base/path.h" |
-#include "omaha/base/safe_format.h" |
-#include "omaha/base/scope_guard.h" |
-#include "omaha/base/synchronized.h" |
-#include "omaha/base/utils.h" |
-#include "omaha/common/config_manager.h" |
-#include "omaha/common/const_cmd_line.h" |
-#include "omaha/common/install_manifest.h" |
-#include "omaha/goopdate/app_manager.h" |
-#include "omaha/goopdate/installer_wrapper.h" |
-#include "omaha/goopdate/model.h" |
-#include "omaha/goopdate/server_resource.h" |
-#include "omaha/goopdate/string_formatter.h" |
- |
-namespace omaha { |
- |
-namespace { |
- |
-// Number of tries when the MSI service is busy. |
-// Updates are silent so we can wait longer. |
-const int kNumMsiAlreadyRunningInteractiveMaxTries = 4; // Up to 35 seconds. |
-const int kNumMsiAlreadyRunningSilentMaxTries = 7; // Up to 6.25 minutes. |
- |
-// TODO(omaha): there can be more install actions for each install event. |
-bool GetInstallActionForEvent( |
- const std::vector<xml::InstallAction>& install_actions, |
- xml::InstallAction::InstallEvent install_event, |
- xml::InstallAction* action) { |
- ASSERT1(action); |
- |
- for (size_t i = 0; i < install_actions.size(); ++i) { |
- if (install_actions[i].install_event == install_event) { |
- *action = install_actions[i]; |
- return true; |
- } |
- } |
- |
- return false; |
-} |
- |
-} // namespace |
- |
-InstallManager::InstallManager(const Lockable* model_lock, bool is_machine) |
- : model_lock_(model_lock), |
- is_machine_(is_machine) { |
- CORE_LOG(L3, (_T("[InstallManager::InstallManager][%d]"), is_machine_)); |
- |
- install_working_dir_ = |
- is_machine ? |
- ConfigManager::Instance()->GetMachineInstallWorkingDir() : |
- ConfigManager::Instance()->GetUserInstallWorkingDir(); |
- CORE_LOG(L3, (_T("[install_working_dir][%s]"), install_working_dir())); |
- |
- VERIFY1(SUCCEEDED(DeleteDirectory(install_working_dir_))); |
- VERIFY1(SUCCEEDED(CreateDir(install_working_dir_, NULL))); |
- |
- installer_wrapper_.reset(new InstallerWrapper(is_machine_)); |
-} |
- |
-InstallManager::~InstallManager() { |
- CORE_LOG(L3, (_T("[InstallManager::~InstallManager]"))); |
-} |
- |
-HRESULT InstallManager::Initialize() { |
- return installer_wrapper_->Initialize(); |
-} |
- |
-CString InstallManager::install_working_dir() const { |
- __mutexScope(model_lock_); |
- return install_working_dir_; |
-} |
- |
-// For each app, set the state to STATE_INSTALLING, install it, and update the |
-// state of the model after it completes. |
-void InstallManager::InstallApp(App* app, const CString& dir) { |
- CORE_LOG(L3, (_T("[InstallManager::InstallApp][0x%p]"), app)); |
- ASSERT1(app); |
- |
- const ConfigManager& cm = *ConfigManager::Instance(); |
- // TODO(omaha): Since we don't currently have is_manual, check the least |
- // restrictive case of true. It would be nice if we had is_manual. We'll see. |
- ASSERT(SUCCEEDED(app->CheckGroupPolicy()), |
- (_T("Installing/updating app for which this is not allowed."))); |
- ASSERT(app->is_eula_accepted() || |
- app->is_install() && app->app_bundle()->is_offline_install(), |
- (_T("update/online install of app for which EULA is not accepted."))); |
- |
- // TODO(omaha3): This needs to be set/passed per app/bundle. |
- const int priority = app->app_bundle()->priority(); |
- const int num_tries = (priority < INSTALL_PRIORITY_HIGH) ? |
- kNumMsiAlreadyRunningSilentMaxTries : |
- kNumMsiAlreadyRunningInteractiveMaxTries; |
- installer_wrapper_->set_num_tries_when_msi_busy(num_tries); |
- |
- AppVersion* next_version = app->next_version(); |
- ASSERT1(app->app_bundle()->is_machine() == is_machine_); |
- |
- const CString current_version_string = app->current_version()->version(); |
- |
- HANDLE primary_token(app->app_bundle()->primary_token()); |
- |
- HRESULT hr = InstallApp(is_machine_, |
- primary_token, |
- current_version_string, |
- *model_lock_, |
- installer_wrapper_.get(), |
- app, |
- dir); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[InstallApp failed][0x%p][0x%08x]"), app, hr)); |
- } |
- |
- app->LogTextAppendFormat(_T("Install result=0x%08x"), hr); |
- |
- ASSERT1(FAILED(hr) == (app->state() == STATE_ERROR)); |
-} |
- |
-HRESULT InstallManager::InstallApp(bool is_machine, |
- HANDLE user_token, |
- const CString& existing_version, |
- const Lockable& model_lock, |
- InstallerWrapper* installer_wrapper, |
- App* app, |
- const CString& dir) { |
- UNREFERENCED_PARAMETER(is_machine); |
- ASSERT1(installer_wrapper); |
- ASSERT1(app); |
- |
- const bool is_update = app->is_update(); |
- |
- CString display_name; |
- GUID app_guid = {0}; |
- CString installer_path; |
- // TODO(omaha3): Consider generating the installerdata file external to the |
- // InstallerWrapper and just adding the path to the arguments. |
- CString manifest_arguments; |
- CString installer_data; |
- CString expected_version; |
- |
- AppManager& app_manager = *AppManager::Instance(); |
- __mutexScope(app_manager.GetRegistryStableStateLock()); |
- |
- // TODO(omaha): If this does not get much simpler, extract method. |
- AppVersion& next_version = *(app->next_version()); |
- ASSERT1(app->app_bundle()->is_machine() == is_machine); |
- |
- CString language = app->app_bundle()->display_language(); |
- |
- // TODO(omaha): review the need for locking below. |
- __mutexBlock(model_lock) { |
- app->Installing(); |
- |
- app_guid = app->app_guid(); |
- |
- // The first package is always the Package Manager for the app. |
- // TODO(omaha3): Use program_to_run here instead of the installer_path. This |
- // will introduce complexity such as having to find the full path and |
- // handling the case where the file is not in the cache. |
- ASSERT1(next_version.GetNumberOfPackages() > 0); |
- if (next_version.GetNumberOfPackages() <= 0) { |
- HRESULT hr = E_FAIL; |
- const CString message = InstallerWrapper::GetMessageForError(hr, |
- CString(), |
- language); |
- app->Error(ErrorContext(hr), message); |
- return hr; |
- } |
- const Package& package_manager = *(next_version.GetPackage(0)); |
- installer_path = ConcatenatePath(dir, package_manager.filename()); |
- |
- xml::InstallAction action; |
- const bool is_event_found = GetInstallActionForEvent( |
- next_version.install_manifest()->install_actions, |
- is_update ? xml::InstallAction::kUpdate : xml::InstallAction::kInstall, |
- &action); |
- ASSERT1(is_event_found); |
- if (is_event_found) { |
- manifest_arguments = action.program_arguments; |
- |
- // If this is an Omaha self-update, append a switch to the argument list |
- // to set the session ID. |
- if (is_update && ::IsEqualGUID(app_guid, kGoopdateGuid)) { |
- SafeCStringAppendFormat(&manifest_arguments, _T(" /%s \"%s\""), |
- kCmdLineSessionId, |
- app->app_bundle()->session_id()); |
- } |
- } |
- |
- installer_data = app->GetInstallData(); |
- |
- expected_version = next_version.install_manifest()->version; |
- |
- // TODO(omaha3): All app key registry writes and reads must be protected by |
- // some lock to prevent race conditions caused by multiple bundles |
- // installing the same app. This includes while writing the pre-install |
- // data, while the installer is running, and while checking application |
- // registration (basically the rest of this method). An app-specific lock |
- // similar to the app install lock in Omaha 2 seems to be appropriate. |
- // (Omaha 2 only took that during install - not updates - though.) |
- // Some app installers may also check the state of other apps (i.e. to check |
- // for version compatibility). Should we protect this case as well? |
- // Is it safest to use the installer lock for this? What is the performance |
- // impact. If we do use the installer lock, it would need to be acquired |
- // here instead of in the InstallerWrapper::InstallApp path. |
- if (!is_update) { |
- HRESULT hr = app_manager.WritePreInstallData(*app); |
- if (FAILED(hr)) { |
- CORE_LOG(LE, (_T("[AppManager::WritePreInstallData failed][0x%08x]"))); |
- const CString message = |
- InstallerWrapper::GetMessageForError(hr, CString(), language); |
- app->Error(ErrorContext(hr), message); |
- return hr; |
- } |
- } |
- } |
- |
- OPT_LOG(L1, (_T("[Installing][%s][%s][%s][%s][%s]"), |
- app->display_name(), |
- GuidToString(app_guid), |
- installer_path, |
- manifest_arguments, |
- installer_data)); |
- |
- InstallerResultInfo result_info; |
- |
- HRESULT hr = installer_wrapper->InstallApp(user_token, |
- app_guid, |
- installer_path, |
- manifest_arguments, |
- installer_data, |
- language, |
- &result_info); |
- |
- OPT_LOG(L1, (_T("[InstallApp returned][0x%x][%s][type:%d][code: %d][%s][%s]"), |
- hr, GuidToString(app_guid), result_info.type, result_info.code, |
- result_info.text, result_info.post_install_launch_command_line)); |
- |
- __mutexScope(model_lock); |
- |
- if (SUCCEEDED(hr)) { |
- ASSERT1(result_info.type == INSTALLER_RESULT_SUCCESS); |
- // Skip checking application registration for Omaha self-updates because the |
- // installer has not completed. |
- if (!::IsEqualGUID(kGoopdateGuid, app_guid)) { |
- hr = app_manager.ReadInstallerRegistrationValues(app); |
- if (SUCCEEDED(hr)) { |
- hr = installer_wrapper->CheckApplicationRegistration( |
- app_guid, |
- next_version.version(), |
- expected_version, |
- existing_version, |
- is_update); |
- } |
- } |
- } else { |
- ASSERT1(result_info.type != INSTALLER_RESULT_SUCCESS); |
- ASSERT1(!result_info.text.IsEmpty() || |
- result_info.type == INSTALLER_RESULT_UNKNOWN); |
- } |
- |
- if (FAILED(hr)) { |
- // If we failed the install job and the product wasn't registered, it's safe |
- // to delete the ClientState key. We need to remove it because it contains |
- // data like "ap", browsertype, language, etc. that need to be cleaned up in |
- // case user tries to install again in the future. |
- if (!is_update && !app_manager.IsAppRegistered(app->app_guid())) { |
- app_manager.RemoveClientState(app->app_guid()); |
- } |
- |
- if (hr == GOOPDATEINSTALL_E_INSTALLER_FAILED) { |
- ASSERT1(!result_info.text.IsEmpty()); |
- app->ReportInstallerComplete(result_info); |
- } else { |
- // TODO(omaha3): If we end up having the installer filename above, pass it |
- // instead of installer_path. |
- const CString message = InstallerWrapper::GetMessageForError( |
- hr, installer_path, language); |
- app->Error(ErrorContext(hr), message); |
- } |
- |
- return hr; |
- } |
- |
- PopulateSuccessfulInstallResultInfo(app, &result_info); |
- |
- app->ReportInstallerComplete(result_info); |
- return S_OK; |
-} |
- |
-// Call this function only when installer succeeded. |
-// This function sets the post install action and url based on installer result |
-// info and app manifest. Note that the action may already have been set by |
-// InstallerWrapper::GetInstallerResultHelper() in some cases. This function |
-// only sets the action when necessary. |
-void InstallManager::PopulateSuccessfulInstallResultInfo( |
- const App* app, |
- InstallerResultInfo* result_info) { |
- ASSERT1(result_info); |
- ASSERT1(result_info->type == INSTALLER_RESULT_SUCCESS); |
- ASSERT1(app); |
- ASSERT1(app->next_version()->install_manifest()); |
- |
- xml::InstallAction action; |
- if (GetInstallActionForEvent( |
- app->next_version()->install_manifest()->install_actions, |
- xml::InstallAction::kPostInstall, |
- &action)) { |
- result_info->post_install_url = action.success_url; |
- |
- if (result_info->post_install_launch_command_line.IsEmpty() && |
- action.success_action == SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD) { |
- CORE_LOG(LW, (_T("[Success action specified launchcmd, but cmd empty]"))); |
- } |
- |
- if (result_info->post_install_action == |
- POST_INSTALL_ACTION_LAUNCH_COMMAND && |
- action.success_action == SUCCESS_ACTION_EXIT_SILENTLY_ON_LAUNCH_CMD) { |
- result_info->post_install_action = |
- POST_INSTALL_ACTION_EXIT_SILENTLY_ON_LAUNCH_COMMAND; |
- } else if (result_info->post_install_action == |
- POST_INSTALL_ACTION_DEFAULT) { |
- if (action.success_action == SUCCESS_ACTION_EXIT_SILENTLY) { |
- result_info->post_install_action = POST_INSTALL_ACTION_EXIT_SILENTLY; |
- } else if (!result_info->post_install_url.IsEmpty()) { |
- result_info->post_install_action = action.terminate_all_browsers ? |
- POST_INSTALL_ACTION_RESTART_ALL_BROWSERS : |
- POST_INSTALL_ACTION_RESTART_BROWSER; |
- } |
- } |
- } |
- |
- // Load message based on post install action if not overridden. |
- if (result_info->text.IsEmpty()) { |
- StringFormatter formatter(app->app_bundle()->display_language()); |
- VERIFY1(SUCCEEDED(formatter.LoadString( |
- IDS_APPLICATION_INSTALLED_SUCCESSFULLY, |
- &result_info->text))); |
- } |
-} |
- |
-} // namespace omaha |