This source file includes following definitions.
- CreateChromeArchiveHelper
- UncompressAndPatchChromeArchive
- AddExistingMultiInstalls
- RenameChromeExecutables
- CheckGroupPolicySettings
- CheckMultiInstallConditions
- CheckAppHostPreconditions
- CheckPreInstallConditions
- CreateTemporaryAndUnpackDirectories
- UninstallProduct
- UninstallProducts
- UninstallBinariesIfUnused
- InstallProducts
- ShowEULADialog
- CreateEULASentinel
- ActivateMetroChrome
- RegisterDevChrome
- HandleNonInstallCmdLineOptions
- ShowRebootDialog
- GetCustomInfo
- InitializeCrashReporting
- UninstallMultiChromeFrameIfPresent
- InstallProductsHelper
- wWinMain
#include "chrome/installer/setup/setup_main.h"
#include <windows.h>
#include <msi.h>
#include <shellapi.h>
#include <shlobj.h>
#include <string>
#include "base/at_exit.h"
#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
#include "breakpad/src/client/windows/handler/exception_handler.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/installer/setup/archive_patch_helper.h"
#include "chrome/installer/setup/install.h"
#include "chrome/installer/setup/install_worker.h"
#include "chrome/installer/setup/setup_constants.h"
#include "chrome/installer/setup/setup_util.h"
#include "chrome/installer/setup/uninstall.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/channel_info.h"
#include "chrome/installer/util/delete_after_reboot_helper.h"
#include "chrome/installer/util/delete_tree_work_item.h"
#include "chrome/installer/util/eula_util.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome/installer/util/google_update_util.h"
#include "chrome/installer/util/helper.h"
#include "chrome/installer/util/html_dialog.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/installation_state.h"
#include "chrome/installer/util/installation_validator.h"
#include "chrome/installer/util/installer_state.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/logging_installer.h"
#include "chrome/installer/util/lzma_util.h"
#include "chrome/installer/util/master_preferences.h"
#include "chrome/installer/util/master_preferences_constants.h"
#include "chrome/installer/util/self_cleaning_temp_dir.h"
#include "chrome/installer/util/shell_util.h"
#include "chrome/installer/util/user_experiment.h"
#include "installer_util_strings.h"
using installer::InstallerState;
using installer::InstallationState;
using installer::InstallationValidator;
using installer::MasterPreferences;
using installer::Product;
using installer::ProductState;
using installer::Products;
const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
const wchar_t kSystemPrincipalSid[] = L"S-1-5-18";
const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
MiniDumpWithProcessThreadData |
MiniDumpWithUnloadedModules |
MiniDumpWithIndirectlyReferencedMemory);
namespace {
scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper(
const base::FilePath& setup_exe,
const CommandLine& command_line,
const installer::InstallerState& installer_state,
const base::FilePath& working_directory) {
base::FilePath compressed_archive(
command_line.GetSwitchValuePath(installer::switches::kInstallArchive));
bool compressed_archive_specified = !compressed_archive.empty();
if (!compressed_archive_specified) {
compressed_archive = setup_exe.DirName().Append(
installer::kChromeCompressedArchive);
}
if (!base::PathExists(compressed_archive)) {
if (compressed_archive_specified) {
LOG(ERROR) << installer::switches::kInstallArchive << "="
<< compressed_archive.value() << " not found.";
}
return scoped_ptr<installer::ArchivePatchHelper>();
}
base::FilePath target(working_directory.Append(installer::kChromeArchive));
DCHECK(!base::PathExists(target));
return scoped_ptr<installer::ArchivePatchHelper>(
new installer::ArchivePatchHelper(working_directory,
compressed_archive,
base::FilePath(),
target));
}
bool UncompressAndPatchChromeArchive(
const installer::InstallationState& original_state,
const installer::InstallerState& installer_state,
installer::ArchivePatchHelper* archive_helper,
installer::ArchiveType* archive_type,
installer::InstallStatus* install_status) {
installer_state.UpdateStage(installer::UNCOMPRESSING);
if (!archive_helper->Uncompress(NULL)) {
*install_status = installer::UNCOMPRESSION_FAILED;
installer_state.WriteInstallerResult(*install_status,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
NULL);
return false;
}
if (base::PathExists(archive_helper->target())) {
*archive_type = installer::FULL_ARCHIVE_TYPE;
return true;
}
base::FilePath patch_source(installer::FindArchiveToPatch(original_state,
installer_state));
if (patch_source.empty()) {
LOG(ERROR) << "Failed to find archive to patch.";
*install_status = installer::DIFF_PATCH_SOURCE_MISSING;
installer_state.WriteInstallerResult(*install_status,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
NULL);
return false;
}
archive_helper->set_patch_source(patch_source);
if ((installer_state.UpdateStage(installer::ENSEMBLE_PATCHING),
!archive_helper->EnsemblePatch()) &&
(installer_state.UpdateStage(installer::BINARY_PATCHING),
!archive_helper->BinaryPatch())) {
*install_status = installer::APPLY_DIFF_PATCH_FAILED;
installer_state.WriteInstallerResult(*install_status,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
NULL);
return false;
}
*archive_type = installer::INCREMENTAL_ARCHIVE_TYPE;
return true;
}
void AddExistingMultiInstalls(const InstallationState& original_state,
InstallerState* installer_state) {
if (installer_state->is_multi_install()) {
for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
BrowserDistribution::Type type =
static_cast<BrowserDistribution::Type>(i);
if (!installer_state->FindProduct(type)) {
const ProductState* state =
original_state.GetProductState(installer_state->system_install(),
type);
if ((state != NULL) && state->is_multi_install()) {
installer_state->AddProductFromState(type, *state);
VLOG(1) << "Product already installed and must be included: "
<< BrowserDistribution::GetSpecificDistribution(type)->
GetDisplayName();
}
}
}
}
}
installer::InstallStatus RenameChromeExecutables(
const InstallationState& original_state,
InstallerState* installer_state) {
AddExistingMultiInstalls(original_state, installer_state);
const base::FilePath &target_path = installer_state->target_path();
base::FilePath chrome_exe(target_path.Append(installer::kChromeExe));
base::FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe));
base::FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe));
installer::SelfCleaningTempDir temp_path;
if (!temp_path.Initialize(target_path.DirName(),
installer::kInstallTempDir)) {
PLOG(ERROR) << "Failed to create Temp directory "
<< target_path.DirName()
.Append(installer::kInstallTempDir).value();
return installer::RENAME_FAILED;
}
scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
install_list->AddMoveTreeWorkItem(chrome_exe.value(),
chrome_old_exe.value(),
temp_path.path().value(),
WorkItem::ALWAYS_MOVE);
install_list->AddMoveTreeWorkItem(chrome_new_exe.value(),
chrome_exe.value(),
temp_path.path().value(),
WorkItem::ALWAYS_MOVE);
install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path());
install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path())->
set_ignore_failure(true);
const Products& products = installer_state->products();
HKEY reg_root = installer_state->root_key();
base::string16 version_key;
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
version_key = (*it)->distribution()->GetVersionKey();
install_list->AddDeleteRegValueWorkItem(
reg_root, version_key, google_update::kRegOldVersionField);
install_list->AddDeleteRegValueWorkItem(
reg_root, version_key, google_update::kRegCriticalVersionField);
install_list->AddDeleteRegValueWorkItem(
reg_root, version_key, google_update::kRegRenameCmdField);
}
installer::InstallStatus ret = installer::RENAME_SUCCESSFUL;
if (!install_list->Do()) {
LOG(ERROR) << "Renaming of executables failed. Rolling back any changes.";
install_list->Rollback();
ret = installer::RENAME_FAILED;
}
VLOG(1) << "Deleting temporary directory " << temp_path.path().value();
return ret;
}
bool CheckGroupPolicySettings(const InstallationState& original_state,
const InstallerState& installer_state,
const Version& new_version,
installer::InstallStatus* status) {
#if !defined(GOOGLE_CHROME_BUILD)
return true;
#else
DCHECK(status);
if (!installer_state.is_multi_install())
return true;
bool settings_are_valid = true;
const bool is_system_install = installer_state.system_install();
BrowserDistribution* const binaries_dist =
installer_state.multi_package_binaries_distribution();
const GoogleUpdateSettings::UpdatePolicy binaries_policy =
GoogleUpdateSettings::GetAppUpdatePolicy(binaries_dist->GetAppGuid(),
NULL);
const Products& products = installer_state.products();
Products::const_iterator scan = products.begin();
for (Products::const_iterator end = products.end(); scan != end; ++scan) {
BrowserDistribution* dist = (*scan)->distribution();
const ProductState* product_state =
original_state.GetProductState(is_system_install, dist->GetType());
if (product_state != NULL &&
product_state->version().CompareTo(new_version) < 0) {
bool is_overridden = false;
GoogleUpdateSettings::UpdatePolicy app_policy =
GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(),
&is_overridden);
if (is_overridden && app_policy != binaries_policy) {
LOG(ERROR) << "Found legacy Group Policy setting for "
<< dist->GetDisplayName() << " (value: " << app_policy
<< ") that does not match the setting for "
<< binaries_dist->GetDisplayName()
<< " (value: " << binaries_policy << ").";
settings_are_valid = false;
}
}
}
if (!settings_are_valid) {
LOG(ERROR) << "Cannot apply update on account of inconsistent "
"Google Update Group Policy settings. Use the Group Policy "
"Editor to set the update policy override for the "
<< binaries_dist->GetDisplayName()
<< " application and try again.";
*status = installer::INCONSISTENT_UPDATE_POLICY;
installer_state.WriteInstallerResult(
*status, IDS_INSTALL_INCONSISTENT_UPDATE_POLICY_BASE, NULL);
}
return settings_are_valid;
#endif
}
bool CheckMultiInstallConditions(const InstallationState& original_state,
InstallerState* installer_state,
installer::InstallStatus* status) {
const Products& products = installer_state->products();
DCHECK(products.size());
const bool system_level = installer_state->system_install();
if (installer_state->is_multi_install()) {
const Product* chrome =
installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
const Product* app_host =
installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST);
const Product* binaries =
installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES);
const ProductState* chrome_state =
original_state.GetProductState(system_level,
BrowserDistribution::CHROME_BROWSER);
if (binaries) {
if (products.size() == 1) {
VLOG(1) << "No products to be updated.";
*status = installer::UNUSED_BINARIES;
installer_state->WriteInstallerResult(*status, 0, NULL);
return false;
}
} else {
if (app_host && !chrome && !chrome_state) {
DCHECK(!system_level);
if (original_state.GetProductState(
true,
BrowserDistribution::CHROME_BROWSER) ||
original_state.GetProductState(
true,
BrowserDistribution::CHROME_BINARIES)) {
VLOG(1) << "Installing/updating App Launcher without binaries.";
} else {
scoped_ptr<Product> binaries_to_add(new Product(
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BINARIES)));
binaries_to_add->SetOption(installer::kOptionMultiInstall, true);
binaries = installer_state->AddProduct(&binaries_to_add);
VLOG(1) <<
"Adding binaries for pre-existing App Launcher installation.";
}
}
return true;
}
if (!chrome && chrome_state) {
scoped_ptr<Product> multi_chrome(new Product(
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BROWSER)));
multi_chrome->SetOption(installer::kOptionMultiInstall, true);
chrome = installer_state->AddProduct(&multi_chrome);
VLOG(1) << "Upgrading existing Chrome browser in multi-install mode.";
}
} else {
const ProductState* product_state = original_state.GetProductState(
system_level, products[0]->distribution()->GetType());
if (product_state != NULL) {
if (product_state->is_multi_install()) {
LOG(ERROR) << "Multi-install "
<< products[0]->distribution()->GetDisplayName()
<< " exists; aborting single install.";
*status = installer::MULTI_INSTALLATION_EXISTS;
installer_state->WriteInstallerResult(*status,
IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL);
return false;
}
}
}
return true;
}
bool CheckAppHostPreconditions(const InstallationState& original_state,
InstallerState* installer_state,
installer::InstallStatus* status) {
if (installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST)) {
if (!installer_state->is_multi_install()) {
LOG(DFATAL) << "App Launcher requires multi install";
*status = installer::APP_HOST_REQUIRES_MULTI_INSTALL;
installer_state->WriteInstallerResult(*status, 0, NULL);
return false;
}
if (installer_state->system_install()) {
LOG(DFATAL) << "App Launcher may only be installed at user-level.";
*status = installer::APP_HOST_REQUIRES_USER_LEVEL;
installer_state->WriteInstallerResult(*status, 0, NULL);
return false;
}
}
return true;
}
bool CheckPreInstallConditions(const InstallationState& original_state,
InstallerState* installer_state,
installer::InstallStatus* status) {
if (!CheckAppHostPreconditions(original_state, installer_state, status)) {
DCHECK_NE(*status, installer::UNKNOWN_STATUS);
return false;
}
AddExistingMultiInstalls(original_state, installer_state);
if (!CheckMultiInstallConditions(original_state, installer_state, status)) {
DCHECK_NE(*status, installer::UNKNOWN_STATUS);
return false;
}
const Products& products = installer_state->products();
if (products.empty()) {
LOG(ERROR)
<< "Not given any products to install and no products found to update.";
*status = installer::CHROME_NOT_INSTALLED;
installer_state->WriteInstallerResult(*status,
IDS_INSTALL_NO_PRODUCTS_TO_UPDATE_BASE, NULL);
return false;
}
if (!installer_state->system_install()) {
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
const Product& product = **it;
BrowserDistribution* browser_dist = product.distribution();
if (browser_dist->GetType() == BrowserDistribution::CHROME_BINARIES)
continue;
const ProductState* user_level_product_state =
original_state.GetProductState(false, browser_dist->GetType());
const ProductState* system_level_product_state =
original_state.GetProductState(true, browser_dist->GetType());
if (user_level_product_state)
continue;
if (system_level_product_state) {
LOG(ERROR) << "Already installed version "
<< system_level_product_state->version().GetString()
<< " at system-level conflicts with this one at user-level.";
if (product.is_chrome()) {
base::FilePath install_path(installer::GetChromeInstallPath(
true,
browser_dist));
if (install_path.empty()) {
*status = installer::OS_ERROR;
installer_state->WriteInstallerResult(*status,
IDS_INSTALL_OS_ERROR_BASE,
NULL);
} else {
*status = installer::EXISTING_VERSION_LAUNCHED;
base::FilePath chrome_exe =
install_path.Append(installer::kChromeExe);
CommandLine cmd(chrome_exe);
cmd.AppendSwitch(switches::kForceFirstRun);
installer_state->WriteInstallerResult(*status, 0, NULL);
VLOG(1) << "Launching existing system-level chrome instead.";
base::LaunchProcess(cmd, base::LaunchOptions(), NULL);
}
} else {
NOTREACHED();
}
return false;
}
}
} else {
if (installer_state->ensure_google_update_present()) {
LOG(DFATAL) << "--" << installer::switches::kEnsureGoogleUpdatePresent
<< " is supported for user-level only.";
*status = installer::APP_HOST_REQUIRES_USER_LEVEL;
installer_state->WriteInstallerResult(*status, 0, NULL);
return false;
}
}
return true;
}
bool CreateTemporaryAndUnpackDirectories(
const InstallerState& installer_state,
installer::SelfCleaningTempDir* temp_path,
base::FilePath* unpack_path) {
DCHECK(temp_path && unpack_path);
if (!temp_path->Initialize(installer_state.target_path().DirName(),
installer::kInstallTempDir)) {
PLOG(ERROR) << "Could not create temporary path.";
return false;
}
VLOG(1) << "Created path " << temp_path->path().value();
if (!base::CreateTemporaryDirInDir(temp_path->path(),
installer::kInstallSourceDir,
unpack_path)) {
PLOG(ERROR) << "Could not create temporary path for unpacked archive.";
return false;
}
return true;
}
installer::InstallStatus UninstallProduct(
const InstallationState& original_state,
const InstallerState& installer_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line,
bool remove_all,
bool force_uninstall,
const Product& product) {
const ProductState* product_state =
original_state.GetProductState(installer_state.system_install(),
product.distribution()->GetType());
if (product_state != NULL) {
VLOG(1) << "version on the system: "
<< product_state->version().GetString();
} else if (!force_uninstall) {
LOG(ERROR) << product.distribution()->GetDisplayName()
<< " not found for uninstall.";
return installer::CHROME_NOT_INSTALLED;
}
return installer::UninstallProduct(
original_state, installer_state, setup_exe, product, remove_all,
force_uninstall, cmd_line);
}
installer::InstallStatus UninstallProducts(
const InstallationState& original_state,
const InstallerState& installer_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line) {
const Products& products = installer_state.products();
CommandLine system_level_cmd(CommandLine::NO_PROGRAM);
const Product* chrome =
installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER);
if (chrome) {
DCHECK(products[0]->is_chrome());
if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) &&
!installer_state.system_install()) {
BrowserDistribution* dist = chrome->distribution();
const base::FilePath system_exe_path(
installer::GetChromeInstallPath(true, dist)
.Append(installer::kChromeExe));
system_level_cmd.SetProgram(system_exe_path);
}
}
if (installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) {
DCHECK(products[products.size() - 1]->is_chrome_binaries());
}
installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL;
installer::InstallStatus prod_status = installer::UNKNOWN_STATUS;
const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall);
const bool remove_all = !cmd_line.HasSwitch(
installer::switches::kDoNotRemoveSharedItems);
for (Products::const_iterator it = products.begin();
install_status != installer::UNINSTALL_CANCELLED && it < products.end();
++it) {
prod_status = UninstallProduct(original_state, installer_state, setup_exe,
cmd_line, remove_all, force, **it);
if (prod_status != installer::UNINSTALL_SUCCESSFUL)
install_status = prod_status;
}
installer::CleanUpInstallationDirectoryAfterUninstall(
original_state, installer_state, setup_exe, &install_status);
installer::DeleteChromeDirectoriesIfEmpty(installer_state.target_path());
if (chrome && cmd_line.HasSwitch(installer::switches::kTriggerActiveSetup))
InstallUtil::TriggerActiveSetupCommand();
if (!system_level_cmd.GetProgram().empty())
base::LaunchProcess(system_level_cmd, base::LaunchOptions(), NULL);
google_update::UninstallGoogleUpdate(installer_state.system_install());
return install_status;
}
void UninstallBinariesIfUnused(
const InstallationState& original_state,
const InstallerState& installer_state,
installer::InstallStatus* install_status) {
if (*install_status != installer::UNUSED_BINARIES ||
installer_state.AreBinariesInUse(original_state)) {
return;
}
LOG(INFO) << "Uninstalling unused binaries";
installer_state.UpdateStage(installer::UNINSTALLING_BINARIES);
const ProductState* binaries_state =
original_state.GetProductState(installer_state.system_install(),
BrowserDistribution::CHROME_BINARIES);
const CommandLine& uninstall_cmd(binaries_state->uninstall_command());
MasterPreferences uninstall_prefs(uninstall_cmd);
InstallerState uninstall_state;
uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, original_state);
*install_status = UninstallProducts(original_state, uninstall_state,
uninstall_cmd.GetProgram(),
uninstall_cmd);
if (IsUninstallSuccess(*install_status)) {
*install_status = installer::UNUSED_BINARIES_UNINSTALLED;
installer_state.WriteInstallerResult(*install_status, 0, NULL);
}
}
installer::InstallStatus InstallProducts(
const InstallationState& original_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line,
const MasterPreferences& prefs,
InstallerState* installer_state,
base::FilePath* installer_directory) {
DCHECK(installer_state);
const bool system_install = installer_state->system_install();
installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE;
bool delegated_to_existing = false;
installer_state->UpdateStage(installer::PRECONDITIONS);
BrowserDistribution::GetSpecificDistribution(installer_state->state_type())->
UpdateInstallStatus(system_install, archive_type, install_status);
if (CheckPreInstallConditions(original_state, installer_state,
&install_status)) {
VLOG(1) << "Installing to " << installer_state->target_path().value();
install_status = InstallProductsHelper(
original_state, setup_exe, cmd_line, prefs, *installer_state,
installer_directory, &archive_type, &delegated_to_existing);
} else {
DCHECK_NE(install_status, installer::UNKNOWN_STATUS);
}
if (cmd_line.HasSwitch(installer::switches::kInstallerData)) {
base::FilePath prefs_path(cmd_line.GetSwitchValuePath(
installer::switches::kInstallerData));
if (!base::DeleteFile(prefs_path, false)) {
LOG(ERROR) << "Failed deleting master preferences file "
<< prefs_path.value()
<< ", scheduling for deletion after reboot.";
ScheduleFileSystemEntityForDeletion(prefs_path);
}
}
if (delegated_to_existing)
return install_status;
const Products& products = installer_state->products();
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
(*it)->distribution()->UpdateInstallStatus(
system_install, archive_type, install_status);
}
UninstallBinariesIfUnused(original_state, *installer_state, &install_status);
installer_state->UpdateStage(installer::NO_STAGE);
return install_status;
}
installer::InstallStatus ShowEULADialog(const base::string16& inner_frame) {
VLOG(1) << "About to show EULA";
base::string16 eula_path = installer::GetLocalizedEulaResource();
if (eula_path.empty()) {
LOG(ERROR) << "No EULA path available";
return installer::EULA_REJECTED;
}
installer::EulaHTMLDialog dlg(eula_path, inner_frame);
installer::EulaHTMLDialog::Outcome outcome = dlg.ShowModal();
if (installer::EulaHTMLDialog::REJECTED == outcome) {
LOG(ERROR) << "EULA rejected or EULA failure";
return installer::EULA_REJECTED;
}
if (installer::EulaHTMLDialog::ACCEPTED_OPT_IN == outcome) {
VLOG(1) << "EULA accepted (opt-in)";
return installer::EULA_ACCEPTED_OPT_IN;
}
VLOG(1) << "EULA accepted (no opt-in)";
return installer::EULA_ACCEPTED;
}
bool CreateEULASentinel(BrowserDistribution* dist) {
base::FilePath eula_sentinel;
if (!InstallUtil::GetSentinelFilePath(installer::kEULASentinelFile, dist,
&eula_sentinel)) {
return false;
}
return (base::CreateDirectory(eula_sentinel.DirName()) &&
base::WriteFile(eula_sentinel, "", 0) != -1);
}
void ActivateMetroChrome() {
wchar_t exe_path[MAX_PATH * 2] = {};
GetModuleFileName(NULL, exe_path, arraysize(exe_path));
bool is_per_user_install = InstallUtil::IsPerUserInstall(exe_path);
base::string16 app_model_id = ShellUtil::GetBrowserModelId(
BrowserDistribution::GetDistribution(), is_per_user_install);
base::win::ScopedComPtr<IApplicationActivationManager> activator;
HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager);
if (SUCCEEDED(hr)) {
DWORD pid = 0;
hr = activator->ActivateApplication(
app_model_id.c_str(), L"open", AO_NONE, &pid);
}
LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. "
<< "hr=" << std::hex << hr;
}
installer::InstallStatus RegisterDevChrome(
const InstallationState& original_state,
const InstallerState& installer_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line) {
BrowserDistribution* chrome_dist =
BrowserDistribution::GetSpecificDistribution(
BrowserDistribution::CHROME_BROWSER);
const ProductState* existing_chrome =
original_state.GetProductState(false,
BrowserDistribution::CHROME_BROWSER);
if (!existing_chrome) {
existing_chrome =
original_state.GetProductState(true, BrowserDistribution::CHROME_BROWSER);
}
if (existing_chrome) {
static const wchar_t kPleaseUninstallYourChromeMessage[] =
L"You already have a full-installation (non-dev) of %1ls, please "
L"uninstall it first using Add/Remove Programs in the control panel.";
base::string16 name(chrome_dist->GetDisplayName());
base::string16 message(
base::StringPrintf(kPleaseUninstallYourChromeMessage, name.c_str()));
LOG(ERROR) << "Aborting operation: another installation of " << name
<< " was found, as a last resort (if the product is not present "
"in Add/Remove Programs), try executing: "
<< existing_chrome->uninstall_command().GetCommandLineString();
MessageBox(NULL, message.c_str(), NULL, MB_ICONERROR);
return installer::INSTALL_FAILED;
}
base::FilePath chrome_exe(
cmd_line.GetSwitchValuePath(installer::switches::kRegisterDevChrome));
if (chrome_exe.empty())
chrome_exe = setup_exe.DirName().Append(installer::kChromeExe);
if (!chrome_exe.IsAbsolute())
chrome_exe = base::MakeAbsoluteFilePath(chrome_exe);
installer::InstallStatus status = installer::FIRST_INSTALL_SUCCESS;
if (base::PathExists(chrome_exe)) {
Product chrome(chrome_dist);
ShellUtil::ShortcutProperties shortcut_properties(ShellUtil::CURRENT_USER);
chrome.AddDefaultShortcutProperties(chrome_exe, &shortcut_properties);
shortcut_properties.set_dual_mode(true);
shortcut_properties.set_pin_to_taskbar(true);
ShellUtil::CreateOrUpdateShortcut(
ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, chrome_dist,
shortcut_properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS);
scoped_ptr<WorkItemList> delegate_execute_list(
WorkItem::CreateWorkItemList());
installer::AddDelegateExecuteWorkItems(
installer_state, chrome_exe.DirName(), Version(), chrome,
delegate_execute_list.get());
delegate_execute_list->Do();
if (ShellUtil::CanMakeChromeDefaultUnattended()) {
ShellUtil::MakeChromeDefault(
chrome_dist, ShellUtil::CURRENT_USER, chrome_exe.value(), true);
} else {
ShellUtil::ShowMakeChromeDefaultSystemUI(chrome_dist, chrome_exe.value());
}
} else {
LOG(ERROR) << "Path not found: " << chrome_exe.value();
status = installer::INSTALL_FAILED;
}
return status;
}
bool HandleNonInstallCmdLineOptions(const InstallationState& original_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line,
InstallerState* installer_state,
int* exit_code) {
bool handled = true;
if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) {
installer::InstallStatus status = installer::SETUP_PATCH_FAILED;
base::ScopedTempDir temp_path;
if (!temp_path.CreateUniqueTempDir()) {
PLOG(ERROR) << "Could not create temporary path.";
} else {
base::FilePath compressed_archive(cmd_line.GetSwitchValuePath(
installer::switches::kUpdateSetupExe));
VLOG(1) << "Opening archive " << compressed_archive.value();
if (installer::ArchivePatchHelper::UncompressAndPatch(
temp_path.path(),
compressed_archive,
setup_exe,
cmd_line.GetSwitchValuePath(installer::switches::kNewSetupExe))) {
status = installer::NEW_VERSION_UPDATED;
}
if (!temp_path.Delete()) {
LOG(WARNING) << "Scheduling temporary path " << temp_path.path().value()
<< " for deletion at reboot.";
ScheduleDirectoryForDeletion(temp_path.path());
}
}
*exit_code = InstallUtil::GetInstallReturnCode(status);
if (*exit_code) {
LOG(WARNING) << "setup.exe patching failed.";
installer_state->WriteInstallerResult(
status, IDS_SETUP_PATCH_FAILED_BASE, NULL);
}
installer_state->UpdateStage(installer::NO_STAGE);
} else if (cmd_line.HasSwitch(installer::switches::kShowEula)) {
base::string16 inner_frame =
cmd_line.GetSwitchValueNative(installer::switches::kShowEula);
*exit_code = ShowEULADialog(inner_frame);
if (installer::EULA_REJECTED != *exit_code) {
if (GoogleUpdateSettings::SetEULAConsent(
original_state, BrowserDistribution::GetDistribution(), true)) {
CreateEULASentinel(BrowserDistribution::GetDistribution());
}
if (cmd_line.HasSwitch(installer::switches::kShowEulaForMetro))
ActivateMetroChrome();
}
} else if (cmd_line.HasSwitch(installer::switches::kConfigureUserSettings)) {
const Product* chrome_install =
installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION;
if (chrome_install && installer_state->system_install()) {
bool force =
cmd_line.HasSwitch(installer::switches::kForceConfigureUserSettings);
installer::HandleActiveSetupForBrowser(installer_state->target_path(),
*chrome_install, force);
status = installer::INSTALL_REPAIRED;
} else {
LOG(DFATAL) << "chrome_install:" << chrome_install
<< ", system_install:" << installer_state->system_install();
}
*exit_code = InstallUtil::GetInstallReturnCode(status);
} else if (cmd_line.HasSwitch(installer::switches::kRegisterDevChrome)) {
installer::InstallStatus status = RegisterDevChrome(
original_state, *installer_state, setup_exe, cmd_line);
*exit_code = InstallUtil::GetInstallReturnCode(status);
} else if (cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser)) {
installer::InstallStatus status = installer::UNKNOWN_STATUS;
const Product* chrome_install =
installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
if (chrome_install) {
DCHECK(IsUserAnAdmin());
base::string16 chrome_exe(cmd_line.GetSwitchValueNative(
installer::switches::kRegisterChromeBrowser));
base::string16 suffix;
if (cmd_line.HasSwitch(
installer::switches::kRegisterChromeBrowserSuffix)) {
suffix = cmd_line.GetSwitchValueNative(
installer::switches::kRegisterChromeBrowserSuffix);
}
if (cmd_line.HasSwitch(installer::switches::kRegisterURLProtocol)) {
base::string16 protocol = cmd_line.GetSwitchValueNative(
installer::switches::kRegisterURLProtocol);
if (ShellUtil::RegisterChromeForProtocol(
chrome_install->distribution(), chrome_exe, suffix, protocol,
false))
status = installer::IN_USE_UPDATED;
} else {
if (ShellUtil::RegisterChromeBrowser(chrome_install->distribution(),
chrome_exe, suffix, false))
status = installer::IN_USE_UPDATED;
}
} else {
LOG(DFATAL) << "Can't register browser - Chrome distribution not found";
}
*exit_code = InstallUtil::GetInstallReturnCode(status);
} else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) {
*exit_code = RenameChromeExecutables(original_state, installer_state);
} else if (cmd_line.HasSwitch(
installer::switches::kRemoveChromeRegistration)) {
base::string16 suffix;
if (cmd_line.HasSwitch(
installer::switches::kRegisterChromeBrowserSuffix)) {
suffix = cmd_line.GetSwitchValueNative(
installer::switches::kRegisterChromeBrowserSuffix);
}
installer::InstallStatus tmp = installer::UNKNOWN_STATUS;
const Product* chrome_install =
installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
DCHECK(chrome_install);
if (chrome_install) {
installer::DeleteChromeRegistrationKeys(*installer_state,
chrome_install->distribution(), HKEY_LOCAL_MACHINE, suffix, &tmp);
}
*exit_code = tmp;
} else if (cmd_line.HasSwitch(installer::switches::kOnOsUpgrade)) {
const Product* chrome_install =
installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION;
if (chrome_install) {
installer::HandleOsUpgradeForBrowser(*installer_state,
*chrome_install);
status = installer::INSTALL_REPAIRED;
} else {
LOG(DFATAL) << "Chrome product not found.";
}
*exit_code = InstallUtil::GetInstallReturnCode(status);
} else if (cmd_line.HasSwitch(installer::switches::kQueryEULAAcceptance)) {
*exit_code = installer::IsEULAAccepted(installer_state->system_install());
} else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) {
int flavor = -1;
base::StringToInt(cmd_line.GetSwitchValueNative(
installer::switches::kInactiveUserToast), &flavor);
std::string experiment_group =
cmd_line.GetSwitchValueASCII(installer::switches::kExperimentGroup);
DCHECK_NE(-1, flavor);
if (flavor == -1) {
*exit_code = installer::UNKNOWN_STATUS;
} else {
const Products& products = installer_state->products();
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
const Product& product = **it;
installer::InactiveUserToastExperiment(
flavor, base::ASCIIToUTF16(experiment_group), product,
installer_state->target_path());
}
}
} else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) {
const Products& products = installer_state->products();
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
const Product& product = **it;
BrowserDistribution* browser_dist = product.distribution();
Version installed_version;
InstallUtil::GetChromeVersion(browser_dist, true, &installed_version);
if (!installed_version.IsValid()) {
LOG(ERROR) << "No installation of "
<< browser_dist->GetDisplayName()
<< " found for system-level toast.";
} else {
product.LaunchUserExperiment(
setup_exe, installer::REENTRY_SYS_UPDATE, true);
}
}
} else if (cmd_line.HasSwitch(installer::switches::kPatch)) {
const std::string patch_type_str(
cmd_line.GetSwitchValueASCII(installer::switches::kPatch));
const base::FilePath input_file(
cmd_line.GetSwitchValuePath(installer::switches::kInputFile));
const base::FilePath patch_file(
cmd_line.GetSwitchValuePath(installer::switches::kPatchFile));
const base::FilePath output_file(
cmd_line.GetSwitchValuePath(installer::switches::kOutputFile));
if (patch_type_str == installer::kCourgette) {
*exit_code = installer::CourgettePatchFiles(input_file,
patch_file,
output_file);
} else if (patch_type_str == installer::kBsdiff) {
*exit_code = installer::BsdiffPatchFiles(input_file,
patch_file,
output_file);
} else {
*exit_code = installer::PATCH_INVALID_ARGUMENTS;
}
} else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) {
BrowserDistribution::Type dist_type = BrowserDistribution::CHROME_BROWSER;
if (installer_state->is_multi_install())
dist_type = BrowserDistribution::CHROME_BINARIES;
BrowserDistribution* dist =
BrowserDistribution::GetSpecificDistribution(dist_type);
bool updates_enabled =
GoogleUpdateSettings::ReenableAutoupdatesForApp(dist->GetAppGuid());
*exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED :
installer::REENABLE_UPDATES_FAILED;
} else {
handled = false;
}
return handled;
}
bool ShowRebootDialog() {
HANDLE token;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&token)) {
LOG(ERROR) << "Failed to open token.";
return false;
}
base::win::ScopedHandle scoped_handle(token);
TOKEN_PRIVILEGES tkp = {0};
LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, FALSE, &tkp, 0,
reinterpret_cast<PTOKEN_PRIVILEGES>(NULL), 0);
if (GetLastError() != ERROR_SUCCESS) {
LOG(ERROR) << "Unable to get shutdown privileges.";
return false;
}
RestartDialog(NULL, NULL, EWX_REBOOT | EWX_FORCEIFHUNG);
return true;
}
google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) {
base::string16 product;
base::string16 version;
scoped_ptr<FileVersionInfo> version_info(
FileVersionInfo::CreateFileVersionInfo(base::FilePath(exe_path)));
if (version_info.get()) {
version = version_info->product_version();
product = version_info->product_short_name();
}
if (version.empty())
version = L"0.1.0.0";
if (product.empty())
product = L"Chrome Installer";
static google_breakpad::CustomInfoEntry ver_entry(L"ver", version.c_str());
static google_breakpad::CustomInfoEntry prod_entry(L"prod", product.c_str());
static google_breakpad::CustomInfoEntry plat_entry(L"plat", L"Win32");
static google_breakpad::CustomInfoEntry type_entry(L"ptype",
L"Chrome Installer");
static google_breakpad::CustomInfoEntry entries[] = {
ver_entry, prod_entry, plat_entry, type_entry };
static google_breakpad::CustomClientInfo custom_info = {
entries, arraysize(entries) };
return &custom_info;
}
scoped_ptr<google_breakpad::ExceptionHandler> InitializeCrashReporting(
bool system_install) {
if (!GoogleUpdateSettings::GetCollectStatsConsent())
return scoped_ptr<google_breakpad::ExceptionHandler>();
base::FilePath temp_directory;
if (!base::GetTempDir(&temp_directory) || temp_directory.empty())
return scoped_ptr<google_breakpad::ExceptionHandler>();
wchar_t exe_path[MAX_PATH * 2] = {0};
GetModuleFileName(NULL, exe_path, arraysize(exe_path));
base::string16 user_sid = kSystemPrincipalSid;
if (!system_install) {
if (!base::win::GetUserSidString(&user_sid)) {
return scoped_ptr<google_breakpad::ExceptionHandler>();
}
}
base::string16 pipe_name = kGoogleUpdatePipeName;
pipe_name += user_sid;
return scoped_ptr<google_breakpad::ExceptionHandler>(
new google_breakpad::ExceptionHandler(
temp_directory.value(), NULL, NULL, NULL,
google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType,
pipe_name.c_str(), GetCustomInfo(exe_path)));
}
void UninstallMultiChromeFrameIfPresent(const CommandLine& cmd_line,
const MasterPreferences& prefs,
InstallationState* original_state,
InstallerState* installer_state) {
if (installer_state->operation() != InstallerState::MULTI_INSTALL &&
installer_state->operation() != InstallerState::MULTI_UPDATE) {
return;
}
const ProductState* chrome_frame_state =
original_state->GetProductState(installer_state->system_install(),
BrowserDistribution::CHROME_FRAME);
if (!chrome_frame_state || !chrome_frame_state->is_multi_install())
return;
LOG(INFO) << "Uninstalling multi-install Chrome Frame.";
installer_state->UpdateStage(installer::UNINSTALLING_CHROME_FRAME);
const CommandLine& uninstall_cmd(chrome_frame_state->uninstall_command());
MasterPreferences uninstall_prefs(uninstall_cmd);
InstallerState uninstall_state;
uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, *original_state);
const Product* chrome_frame_product = uninstall_state.FindProduct(
BrowserDistribution::CHROME_FRAME);
if (chrome_frame_product) {
const bool remove_all = true;
const bool force_uninstall = true;
installer::InstallStatus uninstall_status =
installer::UninstallProduct(*original_state, uninstall_state,
uninstall_cmd.GetProgram(),
*chrome_frame_product, remove_all,
force_uninstall, cmd_line);
VLOG(1) << "Uninstallation of Chrome Frame returned status "
<< uninstall_status;
} else {
LOG(ERROR) << "Chrome Frame not found for uninstall.";
}
original_state->Initialize();
installer_state->Initialize(cmd_line, prefs, *original_state);
}
}
namespace installer {
InstallStatus InstallProductsHelper(
const InstallationState& original_state,
const base::FilePath& setup_exe,
const CommandLine& cmd_line,
const MasterPreferences& prefs,
const InstallerState& installer_state,
base::FilePath* installer_directory,
ArchiveType* archive_type,
bool* delegated_to_existing) {
DCHECK(archive_type);
DCHECK(delegated_to_existing);
const bool system_install = installer_state.system_install();
InstallStatus install_status = UNKNOWN_STATUS;
bool entered_background_mode = AdjustProcessPriority();
VLOG_IF(1, entered_background_mode) << "Entered background processing mode.";
SelfCleaningTempDir temp_path;
base::FilePath unpack_path;
if (!CreateTemporaryAndUnpackDirectories(installer_state, &temp_path,
&unpack_path)) {
installer_state.WriteInstallerResult(TEMP_DIR_FAILED,
IDS_INSTALL_TEMP_DIR_FAILED_BASE,
NULL);
return TEMP_DIR_FAILED;
}
*archive_type = UNKNOWN_ARCHIVE_TYPE;
base::FilePath uncompressed_archive(cmd_line.GetSwitchValuePath(
switches::kUncompressedArchive));
if (uncompressed_archive.empty()) {
scoped_ptr<ArchivePatchHelper> archive_helper(
CreateChromeArchiveHelper(setup_exe, cmd_line, installer_state,
unpack_path));
if (archive_helper) {
VLOG(1) << "Installing Chrome from compressed archive "
<< archive_helper->compressed_archive().value();
if (!UncompressAndPatchChromeArchive(original_state,
installer_state,
archive_helper.get(),
archive_type,
&install_status)) {
DCHECK_NE(install_status, UNKNOWN_STATUS);
return install_status;
}
uncompressed_archive = archive_helper->target();
DCHECK(!uncompressed_archive.empty());
}
}
if (uncompressed_archive.empty())
uncompressed_archive = setup_exe.DirName().Append(kChromeArchive);
if (*archive_type == UNKNOWN_ARCHIVE_TYPE) {
if (uncompressed_archive.empty() ||
!base::PathExists(uncompressed_archive)) {
LOG(ERROR) << "Cannot install Chrome without an uncompressed archive.";
installer_state.WriteInstallerResult(
INVALID_ARCHIVE, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
return INVALID_ARCHIVE;
}
*archive_type = FULL_ARCHIVE_TYPE;
}
if (LzmaUtil::UnPackArchive(uncompressed_archive.value(),
unpack_path.value(),
NULL)) {
installer_state.WriteInstallerResult(
UNCOMPRESSION_FAILED,
IDS_INSTALL_UNCOMPRESSION_FAILED_BASE,
NULL);
return UNCOMPRESSION_FAILED;
}
VLOG(1) << "unpacked to " << unpack_path.value();
base::FilePath src_path(
unpack_path.Append(kInstallSourceChromeDir));
scoped_ptr<Version>
installer_version(GetMaxVersionFromArchiveDir(src_path));
if (!installer_version.get()) {
LOG(ERROR) << "Did not find any valid version in installer.";
install_status = INVALID_ARCHIVE;
installer_state.WriteInstallerResult(install_status,
IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL);
} else {
VLOG(1) << "version to install: " << installer_version->GetString();
bool proceed_with_installation = true;
if (installer_state.operation() == InstallerState::MULTI_INSTALL) {
base::FilePath existing_setup_exe;
if (GetExistingHigherInstaller(original_state, system_install,
*installer_version, &existing_setup_exe)) {
VLOG(1) << "Deferring to existing installer.";
installer_state.UpdateStage(DEFERRING_TO_HIGHER_VERSION);
if (DeferToExistingInstall(existing_setup_exe, cmd_line,
installer_state, temp_path.path(),
&install_status)) {
*delegated_to_existing = true;
return install_status;
}
}
}
uint32 higher_products = 0;
COMPILE_ASSERT(
sizeof(higher_products) * 8 > BrowserDistribution::NUM_TYPES,
too_many_distribution_types_);
const Products& products = installer_state.products();
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
const Product& product = **it;
const ProductState* product_state =
original_state.GetProductState(system_install,
product.distribution()->GetType());
if (product_state != NULL &&
(product_state->version().CompareTo(*installer_version) > 0)) {
LOG(ERROR) << "Higher version of "
<< product.distribution()->GetDisplayName()
<< " is already installed.";
higher_products |= (1 << product.distribution()->GetType());
}
}
if (higher_products != 0) {
COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 4,
add_support_for_new_products_here_);
const uint32 kBrowserBit = 1 << BrowserDistribution::CHROME_BROWSER;
const uint32 kAppHostBit = 1 << BrowserDistribution::CHROME_APP_HOST;
int message_id = 0;
proceed_with_installation = false;
install_status = HIGHER_VERSION_EXISTS;
switch (higher_products) {
case kBrowserBit:
message_id = IDS_INSTALL_HIGHER_VERSION_BASE;
break;
default:
message_id = IDS_INSTALL_HIGHER_VERSION_APP_LAUNCHER_BASE;
break;
}
installer_state.WriteInstallerResult(install_status, message_id, NULL);
}
proceed_with_installation =
proceed_with_installation &&
CheckGroupPolicySettings(original_state, installer_state,
*installer_version, &install_status);
if (proceed_with_installation) {
if (!system_install && installer_state.ensure_google_update_present()) {
if (!google_update::EnsureUserLevelGoogleUpdatePresent()) {
LOG(ERROR) << "Failed to install Google Update";
proceed_with_installation = false;
install_status = INSTALL_OF_GOOGLE_UPDATE_FAILED;
installer_state.WriteInstallerResult(install_status, 0, NULL);
}
}
}
if (proceed_with_installation) {
base::FilePath prefs_source_path(cmd_line.GetSwitchValueNative(
switches::kInstallerData));
install_status = InstallOrUpdateProduct(
original_state, installer_state, setup_exe, uncompressed_archive,
temp_path.path(), src_path, prefs_source_path, prefs,
*installer_version);
int install_msg_base = IDS_INSTALL_FAILED_BASE;
base::string16 chrome_exe;
base::string16 quoted_chrome_exe;
if (install_status == SAME_VERSION_REPAIR_FAILED) {
install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE;
} else if (install_status != INSTALL_FAILED) {
if (installer_state.target_path().empty()) {
install_msg_base = IDS_INSTALL_OS_ERROR_BASE;
install_status = OS_ERROR;
} else {
chrome_exe = installer_state.target_path().Append(kChromeExe).value();
quoted_chrome_exe = L"\"" + chrome_exe + L"\"";
install_msg_base = 0;
}
}
installer_state.UpdateStage(FINISHING);
const Product* chrome_install = prefs.install_chrome() ?
installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) :
NULL;
bool do_not_register_for_update_launch = false;
if (chrome_install) {
prefs.GetBool(master_preferences::kDoNotRegisterForUpdateLaunch,
&do_not_register_for_update_launch);
} else {
do_not_register_for_update_launch = true;
}
bool write_chrome_launch_string =
(!do_not_register_for_update_launch &&
install_status != IN_USE_UPDATED);
installer_state.WriteInstallerResult(install_status, install_msg_base,
write_chrome_launch_string ? "ed_chrome_exe : NULL);
if (install_status == FIRST_INSTALL_SUCCESS) {
VLOG(1) << "First install successful.";
if (chrome_install) {
bool do_not_launch_chrome = false;
prefs.GetBool(master_preferences::kDoNotLaunchChrome,
&do_not_launch_chrome);
if (!system_install && !do_not_launch_chrome)
chrome_install->LaunchChrome(installer_state.target_path());
}
} else if ((install_status == NEW_VERSION_UPDATED) ||
(install_status == IN_USE_UPDATED)) {
const Product* chrome = installer_state.FindProduct(
BrowserDistribution::CHROME_BROWSER);
if (chrome != NULL) {
DCHECK_NE(chrome_exe, base::string16());
RemoveChromeLegacyRegistryKeys(chrome->distribution(), chrome_exe);
}
}
if (prefs.install_chrome_app_launcher() &&
InstallUtil::GetInstallReturnCode(install_status) == 0) {
std::string webstore_item(google_update::GetUntrustedDataValue(
kInstallFromWebstore));
if (!webstore_item.empty()) {
bool success = InstallFromWebstore(webstore_item);
VLOG_IF(1, !success) << "Failed to launch app installation.";
}
}
}
}
{
base::FilePath setup_path(setup_exe);
if (InstallUtil::GetInstallReturnCode(install_status) == 0) {
setup_path = installer_state.GetInstallerDirectory(*installer_version)
.Append(setup_path.BaseName());
}
const Products& products = installer_state.products();
for (Products::const_iterator it = products.begin(); it < products.end();
++it) {
const Product& product = **it;
product.LaunchUserExperiment(setup_path, install_status, system_install);
}
}
if (installer_directory &&
InstallUtil::GetInstallReturnCode(install_status) == 0) {
*installer_directory =
installer_state.GetInstallerDirectory(*installer_version);
}
VLOG(1) << "Deleting temporary directory " << temp_path.path().value();
return install_status;
}
}
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
wchar_t* command_line, int show_command) {
if (!installer::IsProcessorSupported())
return installer::CPU_NOT_SUPPORTED;
base::AtExitManager exit_manager;
CommandLine::Init(0, NULL);
chrome::RegisterPathProvider();
const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess();
installer::InitInstallerLogging(prefs);
const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
VLOG(1) << "Command Line: " << cmd_line.GetCommandLineString();
VLOG(1) << "multi install is " << prefs.is_multi_install();
bool system_install = false;
prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install);
VLOG(1) << "system install is " << system_install;
scoped_ptr<google_breakpad::ExceptionHandler> breakpad(
InitializeCrashReporting(system_install));
InstallationState original_state;
original_state.Initialize();
InstallerState installer_state;
installer_state.Initialize(cmd_line, prefs, original_state);
const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall);
if (!InstallUtil::IsOSSupported()) {
LOG(ERROR) << "Chrome only supports Windows XP or later.";
installer_state.WriteInstallerResult(
installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL);
return installer::OS_NOT_SUPPORTED;
}
base::win::ScopedCOMInitializer com_initializer;
if (!com_initializer.succeeded()) {
installer_state.WriteInstallerResult(
installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL);
return installer::OS_ERROR;
}
if (InstallUtil::IsChromeSxSProcess()) {
if (system_install ||
prefs.is_multi_install() ||
cmd_line.HasSwitch(installer::switches::kForceUninstall) ||
cmd_line.HasSwitch(installer::switches::kMakeChromeDefault) ||
cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser) ||
cmd_line.HasSwitch(installer::switches::kRemoveChromeRegistration) ||
cmd_line.HasSwitch(installer::switches::kInactiveUserToast) ||
cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) {
return installer::SXS_OPTION_NOT_SUPPORTED;
}
}
if (installer::ContainsUnsupportedSwitch(cmd_line))
return installer::UNSUPPORTED_OPTION;
base::FilePath setup_exe;
if (!PathService::Get(base::FILE_EXE, &setup_exe)) {
NOTREACHED();
return installer::OS_ERROR;
}
int exit_code = 0;
if (HandleNonInstallCmdLineOptions(
original_state, setup_exe, cmd_line, &installer_state, &exit_code)) {
return exit_code;
}
if (system_install && !IsUserAnAdmin()) {
if (base::win::GetVersion() >= base::win::VERSION_VISTA &&
!cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) {
CommandLine new_cmd(CommandLine::NO_PROGRAM);
new_cmd.AppendArguments(cmd_line, true);
new_cmd.AppendSwitch(installer::switches::kRunAsAdmin);
if (!new_cmd.HasSwitch(installer::switches::kSystemLevel))
new_cmd.AppendSwitch(installer::switches::kSystemLevel);
DWORD exit_code = installer::UNKNOWN_STATUS;
InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code);
return exit_code;
} else {
LOG(ERROR) << "Non admin user can not install system level Chrome.";
installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS,
IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL);
return installer::INSUFFICIENT_RIGHTS;
}
}
UninstallMultiChromeFrameIfPresent(cmd_line, prefs,
&original_state, &installer_state);
base::FilePath installer_directory;
installer::InstallStatus install_status = installer::UNKNOWN_STATUS;
if (is_uninstall) {
install_status =
UninstallProducts(original_state, installer_state, setup_exe, cmd_line);
} else {
install_status =
InstallProducts(original_state, setup_exe, cmd_line, prefs,
&installer_state, &installer_directory);
}
InstallationValidator::InstallationType installation_type =
InstallationValidator::NO_PRODUCTS;
LOG_IF(ERROR,
!InstallationValidator::ValidateInstallationType(system_install,
&installation_type));
int return_code = 0;
if (!(installer_state.is_msi() && is_uninstall)) {
return_code = InstallUtil::GetInstallReturnCode(install_status);
}
VLOG(1) << "Installation complete, returning: " << return_code;
return return_code;
}