setup_main.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Use of this source code is governed by a BSD-style license that can be 3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// found in the LICENSE file. 4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/setup_main.h" 6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include <windows.h> 8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include <msi.h> 9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include <shellapi.h> 10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include <shlobj.h> 11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include <string> 13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/at_exit.h" 15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/basictypes.h" 16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/command_line.h" 17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/file_util.h" 18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/file_version_info.h" 19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/files/file_path.h" 20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/files/scoped_temp_dir.h" 21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/memory/scoped_ptr.h" 22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/path_service.h" 23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/process/launch.h" 24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/strings/string16.h" 25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/strings/string_number_conversions.h" 26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/strings/string_util.h" 27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/strings/stringprintf.h" 28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/strings/utf_string_conversions.h" 29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/values.h" 30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/registry.h" 31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/scoped_com_initializer.h" 32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/scoped_comptr.h" 33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/scoped_handle.h" 34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/win_util.h" 35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "base/win/windows_version.h" 36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "breakpad/src/client/windows/handler/exception_handler.h" 37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/common/chrome_constants.h" 38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/common/chrome_paths.h" 39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/common/chrome_switches.h" 40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/archive_patch_helper.h" 41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/install.h" 42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/install_worker.h" 43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/setup_constants.h" 44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/setup_util.h" 45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/setup/uninstall.h" 46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/browser_distribution.h" 47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/channel_info.h" 48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/delete_after_reboot_helper.h" 49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/delete_tree_work_item.h" 50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/eula_util.h" 51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/google_update_constants.h" 52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/google_update_settings.h" 53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/google_update_util.h" 54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/helper.h" 55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/html_dialog.h" 56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/install_util.h" 57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/installation_state.h" 58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/installation_validator.h" 59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/installer_state.h" 60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/l10n_string_util.h" 61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/logging_installer.h" 62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/lzma_util.h" 63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/master_preferences.h" 64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/master_preferences_constants.h" 65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/self_cleaning_temp_dir.h" 66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/shell_util.h" 67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "chrome/installer/util/user_experiment.h" 68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "installer_util_strings.h" // NOLINT 70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::InstallerState; 72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::InstallationState; 73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::InstallationValidator; 74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::MasterPreferences; 75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::Product; 76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::ProductState; 77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovusing installer::Products; 78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovconst wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices"; 80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovconst wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; 81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovconst wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; 82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovconst MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( 84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MiniDumpWithProcessThreadData | // Get PEB and TEB. 85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MiniDumpWithUnloadedModules | // Get unloaded modules when available. 86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. 87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovnamespace { 89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Returns NULL if no compressed archive is available for processing, otherwise 91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// returns a patch helper configured to uncompress and patch. 92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovscoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( 93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const base::FilePath& setup_exe, 94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const CommandLine& command_line, 95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const installer::InstallerState& installer_state, 96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const base::FilePath& working_directory) { 97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // A compressed archive is ordinarily given on the command line by the mini 98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // installer. If one was not given, look for chrome.packed.7z next to the 99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // running program. 100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath compressed_archive( 101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov command_line.GetSwitchValuePath(installer::switches::kInstallArchive)); 102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bool compressed_archive_specified = !compressed_archive.empty(); 103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!compressed_archive_specified) { 104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov compressed_archive = setup_exe.DirName().Append( 105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::kChromeCompressedArchive); 106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Fail if no compressed archive is found. 109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!base::PathExists(compressed_archive)) { 110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (compressed_archive_specified) { 111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << installer::switches::kInstallArchive << "=" 112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << compressed_archive.value() << " not found."; 113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return scoped_ptr<installer::ArchivePatchHelper>(); 115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // chrome.7z is either extracted directly from the compressed archive into the 118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // working dir or is the target of patching in the working dir. 119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath target(working_directory.Append(installer::kChromeArchive)); 120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DCHECK(!base::PathExists(target)); 121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Specify an empty path for the patch source since it isn't yet known that 123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // one is needed. It will be supplied in UncompressAndPatchChromeArchive if it 124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // is. 125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return scoped_ptr<installer::ArchivePatchHelper>( 126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov new installer::ArchivePatchHelper(working_directory, 127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov compressed_archive, 128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath(), 129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov target)); 130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Workhorse for producing an uncompressed archive (chrome.7z) given a 133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// chrome.packed.7z containing either a patch file based on the version of 134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// chrome being updated or the full uncompressed archive. Returns true on 135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// success, in which case |archive_type| is populated based on what was found. 136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Returns false on failure, in which case |install_status| contains the error 137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// code and the result is written to the registry (via WriteInstallerResult). 138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovbool UncompressAndPatchChromeArchive( 139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const installer::InstallationState& original_state, 140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const installer::InstallerState& installer_state, 141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::ArchivePatchHelper* archive_helper, 142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::ArchiveType* archive_type, 143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::InstallStatus* install_status) { 144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.UpdateStage(installer::UNCOMPRESSING); 145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!archive_helper->Uncompress(NULL)) { 146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *install_status = installer::UNCOMPRESSION_FAILED; 147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.WriteInstallerResult(*install_status, 148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Short-circuit if uncompression produced the uncompressed archive rather 154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // than a patch file. 155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (base::PathExists(archive_helper->target())) { 156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *archive_type = installer::FULL_ARCHIVE_TYPE; 157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Find the installed version's archive to serve as the source for patching. 161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath patch_source(installer::FindArchiveToPatch(original_state, 162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state)); 163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (patch_source.empty()) { 164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << "Failed to find archive to patch."; 165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *install_status = installer::DIFF_PATCH_SOURCE_MISSING; 166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.WriteInstallerResult(*install_status, 167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov archive_helper->set_patch_source(patch_source); 172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Try courgette first. Failing that, try bspatch. 174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((installer_state.UpdateStage(installer::ENSEMBLE_PATCHING), 175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !archive_helper->EnsemblePatch()) && 176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov (installer_state.UpdateStage(installer::BINARY_PATCHING), 177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov !archive_helper->BinaryPatch())) { 178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *install_status = installer::APPLY_DIFF_PATCH_FAILED; 179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.WriteInstallerResult(*install_status, 180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *archive_type = installer::INCREMENTAL_ARCHIVE_TYPE; 186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// In multi-install, adds all products to |installer_state| that are 190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// multi-installed and must be updated along with the products already present 191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// in |installer_state|. 192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid AddExistingMultiInstalls(const InstallationState& original_state, 193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InstallerState* installer_state) { 194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (installer_state->is_multi_install()) { 195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { 196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::Type type = 197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov static_cast<BrowserDistribution::Type>(i); 198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!installer_state->FindProduct(type)) { 200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const ProductState* state = 201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov original_state.GetProductState(installer_state->system_install(), 202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov type); 203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if ((state != NULL) && state->is_multi_install()) { 204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->AddProductFromState(type, *state); 205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << "Product already installed and must be included: " 206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << BrowserDistribution::GetSpecificDistribution(type)-> 207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GetDisplayName(); 208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function is called when --rename-chrome-exe option is specified on 215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// setup.exe command line. This function assumes an in-use update has happened 216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// for Chrome so there should be a file called new_chrome.exe on the file 217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// system and a key called 'opv' in the registry. This function will move 218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. 219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// This function also deletes elevation policies associated with the old version 220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// if they exist. 221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovinstaller::InstallStatus RenameChromeExecutables( 222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const InstallationState& original_state, 223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InstallerState* installer_state) { 224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // See what products are already installed in multi mode. When we do the 225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // rename for multi installs, we must update all installations since they 226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // share the binaries. 227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov AddExistingMultiInstalls(original_state, installer_state); 228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const base::FilePath &target_path = installer_state->target_path(); 229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath chrome_exe(target_path.Append(installer::kChromeExe)); 230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); 231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::FilePath chrome_old_exe(target_path.Append(installer::kChromeOldExe)); 232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Create a temporary backup directory on the same volume as chrome.exe so 234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // that moving in-use files doesn't lead to trouble. 235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::SelfCleaningTempDir temp_path; 236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!temp_path.Initialize(target_path.DirName(), 237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::kInstallTempDir)) { 238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov PLOG(ERROR) << "Failed to create Temp directory " 239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << target_path.DirName() 240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov .Append(installer::kInstallTempDir).value(); 241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return installer::RENAME_FAILED; 242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); 244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Move chrome.exe to old_chrome.exe, then move new_chrome.exe to chrome.exe. 245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddMoveTreeWorkItem(chrome_exe.value(), 246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov chrome_old_exe.value(), 247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov temp_path.path().value(), 248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WorkItem::ALWAYS_MOVE); 249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddMoveTreeWorkItem(chrome_new_exe.value(), 250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov chrome_exe.value(), 251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov temp_path.path().value(), 252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov WorkItem::ALWAYS_MOVE); 253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path()); 254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // old_chrome.exe is still in use in most cases, so ignore failures here. 255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path())-> 256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov set_ignore_failure(true); 257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Add work items to delete the "opv", "cpv", and "cmd" values from all 259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // products we're operating on (which including the multi-install binaries). 260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Products& products = installer_state->products(); 261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov HKEY reg_root = installer_state->root_key(); 262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov base::string16 version_key; 263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (Products::const_iterator it = products.begin(); it < products.end(); 264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ++it) { 265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov version_key = (*it)->distribution()->GetVersionKey(); 266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddDeleteRegValueWorkItem(reg_root, 267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov version_key, 268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov KEY_WOW64_32KEY, 269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov google_update::kRegOldVersionField); 270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddDeleteRegValueWorkItem( 271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov reg_root, 272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov version_key, 273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov KEY_WOW64_32KEY, 274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov google_update::kRegCriticalVersionField); 275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->AddDeleteRegValueWorkItem(reg_root, 276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov version_key, 277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov KEY_WOW64_32KEY, 278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov google_update::kRegRenameCmdField); 279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::InstallStatus ret = installer::RENAME_SUCCESSFUL; 281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!install_list->Do()) { 282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; 283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov install_list->Rollback(); 284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov ret = installer::RENAME_FAILED; 285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // temp_path's dtor will take care of deleting or scheduling itself for 287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // deletion at reboot when this scope closes. 288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); 289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return ret; 291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// For each product that is being updated (i.e., already installed at an earlier 294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// version), see if that product has an update policy override that differs from 295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// that for the binaries. If any are found, fail with an error indicating that 296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the Group Policy settings are in an inconsistent state. Do not do this test 297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// for same-version installs, since it would be unkind to block attempts to 298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// repair a corrupt installation. This function returns false when installation 299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// should be halted, in which case |status| contains the relevant exit code and 300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// the proper installer result has been written to the registry. 301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovbool CheckGroupPolicySettings(const InstallationState& original_state, 302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const InstallerState& installer_state, 303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Version& new_version, 304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::InstallStatus* status) { 305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if !defined(GOOGLE_CHROME_BUILD) 306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Chromium builds are not updated via Google Update, so there are no 307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Group Policy settings to consult. 308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else 310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DCHECK(status); 311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Single installs are always in good shape. 313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!installer_state.is_multi_install()) 314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bool settings_are_valid = true; 317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const bool is_system_install = installer_state.system_install(); 318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution* const binaries_dist = 319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.multi_package_binaries_distribution(); 320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Get the update policy for the binaries. 322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const GoogleUpdateSettings::UpdatePolicy binaries_policy = 323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GoogleUpdateSettings::GetAppUpdatePolicy(binaries_dist->GetAppGuid(), 324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov NULL); 325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for differing update policies for all of the products being updated. 327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Products& products = installer_state.products(); 328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov Products::const_iterator scan = products.begin(); 329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov for (Products::const_iterator end = products.end(); scan != end; ++scan) { 330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution* dist = (*scan)->distribution(); 331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const ProductState* product_state = 332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov original_state.GetProductState(is_system_install, dist->GetType()); 333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Is an earlier version of this product already installed? 334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (product_state != NULL && 335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov product_state->version().CompareTo(new_version) < 0) { 336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov bool is_overridden = false; 337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GoogleUpdateSettings::UpdatePolicy app_policy = 338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov GoogleUpdateSettings::GetAppUpdatePolicy(dist->GetAppGuid(), 339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov &is_overridden); 340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (is_overridden && app_policy != binaries_policy) { 341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << "Found legacy Group Policy setting for " 342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << dist->GetDisplayName() << " (value: " << app_policy 343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << ") that does not match the setting for " 344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << binaries_dist->GetDisplayName() 345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << " (value: " << binaries_policy << ")."; 346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov settings_are_valid = false; 347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!settings_are_valid) { 352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // TODO(grt): add " See http://goo.gl/+++ for details." to the end of this 353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // log message and to the IDS_INSTALL_INCONSISTENT_UPDATE_POLICY string once 354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // we have a help center article that explains why this error is being 355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // reported and how to resolve it. 356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << "Cannot apply update on account of inconsistent " 357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov "Google Update Group Policy settings. Use the Group Policy " 358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov "Editor to set the update policy override for the " 359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << binaries_dist->GetDisplayName() 360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << " application and try again."; 361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status = installer::INCONSISTENT_UPDATE_POLICY; 362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state.WriteInstallerResult( 363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status, IDS_INSTALL_INCONSISTENT_UPDATE_POLICY_BASE, NULL); 364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return settings_are_valid; 367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif // defined(GOOGLE_CHROME_BUILD) 368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// If only the binaries are being updated, fail. 371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// If any product is being installed in single-mode that already exists in 372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// multi-mode, fail. 373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovbool CheckMultiInstallConditions(const InstallationState& original_state, 374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InstallerState* installer_state, 375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::InstallStatus* status) { 376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Products& products = installer_state->products(); 377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DCHECK(products.size()); 378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const bool system_level = installer_state->system_install(); 380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (installer_state->is_multi_install()) { 382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Product* chrome = 383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Product* app_host = 385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST); 386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const Product* binaries = 387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES); 388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const ProductState* chrome_state = 389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov original_state.GetProductState(system_level, 390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::CHROME_BROWSER); 391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (binaries) { 393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (products.size() == 1) { 394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // There are no products aside from the binaries, so there is no update 395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // to be applied. This can happen after multi-install Chrome Frame is 396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // migrated to single-install. This is treated as an update failure 397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // unless the binaries are not in-use, in which case they will be 398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // uninstalled and success will be reported (see handling in wWinMain). 399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << "No products to be updated."; 400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status = installer::UNUSED_BINARIES; 401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->WriteInstallerResult(*status, 0, NULL); 402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This will only be hit if --multi-install is given with no products, or 406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // if the app host is being installed and doesn't need the binaries at 407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // user-level. 408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // The former case might be due to a request by an orphaned Application 409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Host to re-install the binaries. Thus we add them to the installation. 410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // The latter case is fine and we let it be. 411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // If this is not an app host install and the binaries are not already 412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // present, the installation will fail later due to a lack of products to 413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // install. 414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (app_host && !chrome && !chrome_state) { 415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov DCHECK(!system_level); 416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // App Host may use Chrome/Chrome binaries at system-level. 417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (original_state.GetProductState( 418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov true, // system 419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::CHROME_BROWSER) || 420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov original_state.GetProductState( 421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov true, // system 422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::CHROME_BINARIES)) { 423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << "Installing/updating App Launcher without binaries."; 424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Somehow the binaries were present when the quick-enable app host 426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // command was run, but now they appear to be missing. 427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Force binaries to be installed/updated. 428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scoped_ptr<Product> binaries_to_add(new Product( 429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::GetSpecificDistribution( 430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::CHROME_BINARIES))); 431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov binaries_to_add->SetOption(installer::kOptionMultiInstall, true); 432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov binaries = installer_state->AddProduct(&binaries_to_add); 433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << 434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov "Adding binaries for pre-existing App Launcher installation."; 435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!chrome && chrome_state) { 442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // A product other than Chrome is being installed in multi-install mode, 443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // and Chrome is already present. Add Chrome to the set of products 444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // (making it multi-install in the process) so that it is updated, too. 445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov scoped_ptr<Product> multi_chrome(new Product( 446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::GetSpecificDistribution( 447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov BrowserDistribution::CHROME_BROWSER))); 448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov multi_chrome->SetOption(installer::kOptionMultiInstall, true); 449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov chrome = installer_state->AddProduct(&multi_chrome); 450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov VLOG(1) << "Upgrading existing Chrome browser in multi-install mode."; 451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } else { 453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // This is a non-multi installation. 454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Check for an existing installation of the product. 456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov const ProductState* product_state = original_state.GetProductState( 457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov system_level, products[0]->distribution()->GetType()); 458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (product_state != NULL) { 459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // Block downgrades from multi-install to single-install. 460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (product_state->is_multi_install()) { 461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(ERROR) << "Multi-install " 462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << products[0]->distribution()->GetDisplayName() 463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov << " exists; aborting single install."; 464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status = installer::MULTI_INSTALLATION_EXISTS; 465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->WriteInstallerResult(*status, 466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov IDS_INSTALL_MULTI_INSTALLATION_EXISTS_BASE, NULL); 467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Checks app host pre-install conditions, specifically that this is a 476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// user-level multi-install. When the pre-install conditions are not 477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// satisfied, the result is written to the registry (via WriteInstallerResult), 478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// |status| is set appropriately, and false is returned. 479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovbool CheckAppHostPreconditions(const InstallationState& original_state, 480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov InstallerState* installer_state, 481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer::InstallStatus* status) { 482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (installer_state->FindProduct(BrowserDistribution::CHROME_APP_HOST)) { 483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (!installer_state->is_multi_install()) { 484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(DFATAL) << "App Launcher requires multi install"; 485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status = installer::APP_HOST_REQUIRES_MULTI_INSTALL; 486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // No message string since there is nothing a user can do. 487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->WriteInstallerResult(*status, 0, NULL); 488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov if (installer_state->system_install()) { 492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov LOG(DFATAL) << "App Launcher may only be installed at user-level."; 493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov *status = installer::APP_HOST_REQUIRES_USER_LEVEL; 494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov // No message string since there is nothing a user can do. 495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov installer_state->WriteInstallerResult(*status, 0, NULL); 496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return false; 497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov } 499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov return true; 501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov} 502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov 503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Checks for compatibility between the current state of the system and the 504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// desired operation. Also applies policy that mutates the desired operation; 505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// specifically, the |installer_state| object. 506// Also blocks simultaneous user-level and system-level installs. In the case 507// of trying to install user-level Chrome when system-level exists, the 508// existing system-level Chrome is launched. 509// When the pre-install conditions are not satisfied, the result is written to 510// the registry (via WriteInstallerResult), |status| is set appropriately, and 511// false is returned. 512bool CheckPreInstallConditions(const InstallationState& original_state, 513 InstallerState* installer_state, 514 installer::InstallStatus* status) { 515 if (!CheckAppHostPreconditions(original_state, installer_state, status)) { 516 DCHECK_NE(*status, installer::UNKNOWN_STATUS); 517 return false; 518 } 519 520 // See what products are already installed in multi mode. When we do multi 521 // installs, we must upgrade all installations since they share the binaries. 522 AddExistingMultiInstalls(original_state, installer_state); 523 524 if (!CheckMultiInstallConditions(original_state, installer_state, status)) { 525 DCHECK_NE(*status, installer::UNKNOWN_STATUS); 526 return false; 527 } 528 529 const Products& products = installer_state->products(); 530 if (products.empty()) { 531 // We haven't been given any products on which to operate. 532 LOG(ERROR) 533 << "Not given any products to install and no products found to update."; 534 *status = installer::CHROME_NOT_INSTALLED; 535 installer_state->WriteInstallerResult(*status, 536 IDS_INSTALL_NO_PRODUCTS_TO_UPDATE_BASE, NULL); 537 return false; 538 } 539 540 if (!installer_state->system_install()) { 541 // This is a user-level installation. Make sure that we are not installing 542 // on top of an existing system-level installation. 543 for (Products::const_iterator it = products.begin(); it < products.end(); 544 ++it) { 545 const Product& product = **it; 546 BrowserDistribution* browser_dist = product.distribution(); 547 548 // Skip over the binaries, as it's okay for them to be at both levels 549 // for different products. 550 if (browser_dist->GetType() == BrowserDistribution::CHROME_BINARIES) 551 continue; 552 553 const ProductState* user_level_product_state = 554 original_state.GetProductState(false, browser_dist->GetType()); 555 const ProductState* system_level_product_state = 556 original_state.GetProductState(true, browser_dist->GetType()); 557 558 // Allow upgrades to proceed so that out-of-date versions are not left 559 // around. 560 if (user_level_product_state) 561 continue; 562 563 // This is a new user-level install... 564 565 if (system_level_product_state) { 566 // ... and the product already exists at system-level. 567 LOG(ERROR) << "Already installed version " 568 << system_level_product_state->version().GetString() 569 << " at system-level conflicts with this one at user-level."; 570 if (product.is_chrome()) { 571 // Instruct Google Update to launch the existing system-level Chrome. 572 // There should be no error dialog. 573 base::FilePath install_path(installer::GetChromeInstallPath( 574 true, // system 575 browser_dist)); 576 if (install_path.empty()) { 577 // Give up if we failed to construct the install path. 578 *status = installer::OS_ERROR; 579 installer_state->WriteInstallerResult(*status, 580 IDS_INSTALL_OS_ERROR_BASE, 581 NULL); 582 } else { 583 *status = installer::EXISTING_VERSION_LAUNCHED; 584 base::FilePath chrome_exe = 585 install_path.Append(installer::kChromeExe); 586 CommandLine cmd(chrome_exe); 587 cmd.AppendSwitch(switches::kForceFirstRun); 588 installer_state->WriteInstallerResult(*status, 0, NULL); 589 VLOG(1) << "Launching existing system-level chrome instead."; 590 base::LaunchProcess(cmd, base::LaunchOptions(), NULL); 591 } 592 } else { 593 // It's no longer possible for |product| to be anything other than 594 // Chrome. 595 NOTREACHED(); 596 } 597 return false; 598 } 599 } 600 601 } else { // System-level install. 602 // --ensure-google-update-present is supported for user-level only. 603 // The flag is generic, but its primary use case involves App Host. 604 if (installer_state->ensure_google_update_present()) { 605 LOG(DFATAL) << "--" << installer::switches::kEnsureGoogleUpdatePresent 606 << " is supported for user-level only."; 607 *status = installer::APP_HOST_REQUIRES_USER_LEVEL; 608 // No message string since there is nothing a user can do. 609 installer_state->WriteInstallerResult(*status, 0, NULL); 610 return false; 611 } 612 } 613 614 return true; 615} 616 617// Initializes |temp_path| to "Temp" within the target directory, and 618// |unpack_path| to a random directory beginning with "source" within 619// |temp_path|. Returns false on error. 620bool CreateTemporaryAndUnpackDirectories( 621 const InstallerState& installer_state, 622 installer::SelfCleaningTempDir* temp_path, 623 base::FilePath* unpack_path) { 624 DCHECK(temp_path && unpack_path); 625 626 if (!temp_path->Initialize(installer_state.target_path().DirName(), 627 installer::kInstallTempDir)) { 628 PLOG(ERROR) << "Could not create temporary path."; 629 return false; 630 } 631 VLOG(1) << "Created path " << temp_path->path().value(); 632 633 if (!base::CreateTemporaryDirInDir(temp_path->path(), 634 installer::kInstallSourceDir, 635 unpack_path)) { 636 PLOG(ERROR) << "Could not create temporary path for unpacked archive."; 637 return false; 638 } 639 640 return true; 641} 642 643installer::InstallStatus UninstallProduct( 644 const InstallationState& original_state, 645 const InstallerState& installer_state, 646 const base::FilePath& setup_exe, 647 const CommandLine& cmd_line, 648 bool remove_all, 649 bool force_uninstall, 650 const Product& product) { 651 const ProductState* product_state = 652 original_state.GetProductState(installer_state.system_install(), 653 product.distribution()->GetType()); 654 if (product_state != NULL) { 655 VLOG(1) << "version on the system: " 656 << product_state->version().GetString(); 657 } else if (!force_uninstall) { 658 LOG(ERROR) << product.distribution()->GetDisplayName() 659 << " not found for uninstall."; 660 return installer::CHROME_NOT_INSTALLED; 661 } 662 663 return installer::UninstallProduct( 664 original_state, installer_state, setup_exe, product, remove_all, 665 force_uninstall, cmd_line); 666} 667 668installer::InstallStatus UninstallProducts( 669 const InstallationState& original_state, 670 const InstallerState& installer_state, 671 const base::FilePath& setup_exe, 672 const CommandLine& cmd_line) { 673 const Products& products = installer_state.products(); 674 675 // System-level Chrome will be launched via this command if its program gets 676 // set below. 677 CommandLine system_level_cmd(CommandLine::NO_PROGRAM); 678 679 const Product* chrome = 680 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER); 681 if (chrome) { 682 // InstallerState::Initialize always puts Chrome first, and we rely on that 683 // here for this reason: if Chrome is in-use, the user will be prompted to 684 // confirm uninstallation. Upon cancel, we should not continue with the 685 // other products. 686 DCHECK(products[0]->is_chrome()); 687 688 if (cmd_line.HasSwitch(installer::switches::kSelfDestruct) && 689 !installer_state.system_install()) { 690 BrowserDistribution* dist = chrome->distribution(); 691 const base::FilePath system_exe_path( 692 installer::GetChromeInstallPath(true, dist) 693 .Append(installer::kChromeExe)); 694 system_level_cmd.SetProgram(system_exe_path); 695 } 696 } 697 if (installer_state.FindProduct(BrowserDistribution::CHROME_BINARIES)) { 698 // Chrome Binaries should be last; if something else is cancelled, they 699 // should stay. 700 DCHECK(products[products.size() - 1]->is_chrome_binaries()); 701 } 702 703 installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL; 704 installer::InstallStatus prod_status = installer::UNKNOWN_STATUS; 705 const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); 706 const bool remove_all = !cmd_line.HasSwitch( 707 installer::switches::kDoNotRemoveSharedItems); 708 709 for (Products::const_iterator it = products.begin(); 710 install_status != installer::UNINSTALL_CANCELLED && it < products.end(); 711 ++it) { 712 prod_status = UninstallProduct(original_state, installer_state, setup_exe, 713 cmd_line, remove_all, force, **it); 714 if (prod_status != installer::UNINSTALL_SUCCESSFUL) 715 install_status = prod_status; 716 } 717 718 installer::CleanUpInstallationDirectoryAfterUninstall( 719 original_state, installer_state, setup_exe, &install_status); 720 721 // The app and vendor dirs may now be empty. Make a last-ditch attempt to 722 // delete them. 723 installer::DeleteChromeDirectoriesIfEmpty(installer_state.target_path()); 724 725 // Trigger Active Setup if it was requested for the chrome product. This needs 726 // to be done after the UninstallProduct calls as some of them might 727 // otherwise terminate the process launched by TriggerActiveSetupCommand(). 728 if (chrome && cmd_line.HasSwitch(installer::switches::kTriggerActiveSetup)) 729 InstallUtil::TriggerActiveSetupCommand(); 730 731 if (!system_level_cmd.GetProgram().empty()) 732 base::LaunchProcess(system_level_cmd, base::LaunchOptions(), NULL); 733 734 // Tell Google Update that an uninstall has taken place. 735 // Ignore the return value: success or failure of Google Update 736 // has no bearing on the success or failure of Chrome's uninstallation. 737 google_update::UninstallGoogleUpdate(installer_state.system_install()); 738 739 return install_status; 740} 741 742// Uninstall the binaries if they are the only product present and they're not 743// in-use. 744void UninstallBinariesIfUnused( 745 const InstallationState& original_state, 746 const InstallerState& installer_state, 747 installer::InstallStatus* install_status) { 748 // Early exit if the binaries are still in use. 749 if (*install_status != installer::UNUSED_BINARIES || 750 installer_state.AreBinariesInUse(original_state)) { 751 return; 752 } 753 754 LOG(INFO) << "Uninstalling unused binaries"; 755 installer_state.UpdateStage(installer::UNINSTALLING_BINARIES); 756 757 // Simulate the uninstall as coming from the installed version. 758 const ProductState* binaries_state = 759 original_state.GetProductState(installer_state.system_install(), 760 BrowserDistribution::CHROME_BINARIES); 761 const CommandLine& uninstall_cmd(binaries_state->uninstall_command()); 762 MasterPreferences uninstall_prefs(uninstall_cmd); 763 InstallerState uninstall_state; 764 uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, original_state); 765 766 *install_status = UninstallProducts(original_state, uninstall_state, 767 uninstall_cmd.GetProgram(), 768 uninstall_cmd); 769 770 // Report that the binaries were uninstalled if they were. This translates 771 // into a successful install return code. 772 if (IsUninstallSuccess(*install_status)) { 773 *install_status = installer::UNUSED_BINARIES_UNINSTALLED; 774 installer_state.WriteInstallerResult(*install_status, 0, NULL); 775 } 776} 777 778installer::InstallStatus InstallProducts( 779 const InstallationState& original_state, 780 const base::FilePath& setup_exe, 781 const CommandLine& cmd_line, 782 const MasterPreferences& prefs, 783 InstallerState* installer_state, 784 base::FilePath* installer_directory) { 785 DCHECK(installer_state); 786 const bool system_install = installer_state->system_install(); 787 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 788 installer::ArchiveType archive_type = installer::UNKNOWN_ARCHIVE_TYPE; 789 bool delegated_to_existing = false; 790 installer_state->UpdateStage(installer::PRECONDITIONS); 791 // The stage provides more fine-grained information than -multifail, so remove 792 // the -multifail suffix from the Google Update "ap" value. 793 BrowserDistribution::GetSpecificDistribution(installer_state->state_type())-> 794 UpdateInstallStatus(system_install, archive_type, install_status); 795 if (CheckPreInstallConditions(original_state, installer_state, 796 &install_status)) { 797 VLOG(1) << "Installing to " << installer_state->target_path().value(); 798 install_status = InstallProductsHelper( 799 original_state, setup_exe, cmd_line, prefs, *installer_state, 800 installer_directory, &archive_type, &delegated_to_existing); 801 } else { 802 // CheckPreInstallConditions must set the status on failure. 803 DCHECK_NE(install_status, installer::UNKNOWN_STATUS); 804 } 805 806 // Delete the master preferences file if present. Note that we do not care 807 // about rollback here and we schedule for deletion on reboot if the delete 808 // fails. As such, we do not use DeleteTreeWorkItem. 809 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { 810 base::FilePath prefs_path(cmd_line.GetSwitchValuePath( 811 installer::switches::kInstallerData)); 812 if (!base::DeleteFile(prefs_path, false)) { 813 LOG(ERROR) << "Failed deleting master preferences file " 814 << prefs_path.value() 815 << ", scheduling for deletion after reboot."; 816 ScheduleFileSystemEntityForDeletion(prefs_path); 817 } 818 } 819 820 // Early exit if this setup.exe delegated to another, since that one would 821 // have taken care of UpdateInstallStatus and UpdateStage. 822 if (delegated_to_existing) 823 return install_status; 824 825 const Products& products = installer_state->products(); 826 for (Products::const_iterator it = products.begin(); it < products.end(); 827 ++it) { 828 (*it)->distribution()->UpdateInstallStatus( 829 system_install, archive_type, install_status); 830 } 831 832 UninstallBinariesIfUnused(original_state, *installer_state, &install_status); 833 834 installer_state->UpdateStage(installer::NO_STAGE); 835 return install_status; 836} 837 838installer::InstallStatus ShowEULADialog(const base::string16& inner_frame) { 839 VLOG(1) << "About to show EULA"; 840 base::string16 eula_path = installer::GetLocalizedEulaResource(); 841 if (eula_path.empty()) { 842 LOG(ERROR) << "No EULA path available"; 843 return installer::EULA_REJECTED; 844 } 845 // Newer versions of the caller pass an inner frame parameter that must 846 // be given to the html page being launched. 847 installer::EulaHTMLDialog dlg(eula_path, inner_frame); 848 installer::EulaHTMLDialog::Outcome outcome = dlg.ShowModal(); 849 if (installer::EulaHTMLDialog::REJECTED == outcome) { 850 LOG(ERROR) << "EULA rejected or EULA failure"; 851 return installer::EULA_REJECTED; 852 } 853 if (installer::EulaHTMLDialog::ACCEPTED_OPT_IN == outcome) { 854 VLOG(1) << "EULA accepted (opt-in)"; 855 return installer::EULA_ACCEPTED_OPT_IN; 856 } 857 VLOG(1) << "EULA accepted (no opt-in)"; 858 return installer::EULA_ACCEPTED; 859} 860 861// Creates the sentinel indicating that the EULA was required and has been 862// accepted. 863bool CreateEULASentinel(BrowserDistribution* dist) { 864 base::FilePath eula_sentinel; 865 if (!InstallUtil::GetEULASentinelFilePath(&eula_sentinel)) 866 return false; 867 868 return (base::CreateDirectory(eula_sentinel.DirName()) && 869 base::WriteFile(eula_sentinel, "", 0) != -1); 870} 871 872void ActivateMetroChrome() { 873 // Check to see if we're per-user or not. Need to do this since we may 874 // not have been invoked with --system-level even for a machine install. 875 wchar_t exe_path[MAX_PATH * 2] = {}; 876 GetModuleFileName(NULL, exe_path, arraysize(exe_path)); 877 bool is_per_user_install = InstallUtil::IsPerUserInstall(exe_path); 878 879 base::string16 app_model_id = ShellUtil::GetBrowserModelId( 880 BrowserDistribution::GetDistribution(), is_per_user_install); 881 882 base::win::ScopedComPtr<IApplicationActivationManager> activator; 883 HRESULT hr = activator.CreateInstance(CLSID_ApplicationActivationManager); 884 if (SUCCEEDED(hr)) { 885 DWORD pid = 0; 886 hr = activator->ActivateApplication( 887 app_model_id.c_str(), L"open", AO_NONE, &pid); 888 } 889 890 LOG_IF(ERROR, FAILED(hr)) << "Tried and failed to launch Metro Chrome. " 891 << "hr=" << std::hex << hr; 892} 893 894installer::InstallStatus RegisterDevChrome( 895 const InstallationState& original_state, 896 const InstallerState& installer_state, 897 const base::FilePath& setup_exe, 898 const CommandLine& cmd_line) { 899 BrowserDistribution* chrome_dist = 900 BrowserDistribution::GetSpecificDistribution( 901 BrowserDistribution::CHROME_BROWSER); 902 903 // Only proceed with registering a dev chrome if no real Chrome installation 904 // of the same distribution are present on this system. 905 const ProductState* existing_chrome = 906 original_state.GetProductState(false, 907 BrowserDistribution::CHROME_BROWSER); 908 if (!existing_chrome) { 909 existing_chrome = 910 original_state.GetProductState(true, BrowserDistribution::CHROME_BROWSER); 911 } 912 if (existing_chrome) { 913 static const wchar_t kPleaseUninstallYourChromeMessage[] = 914 L"You already have a full-installation (non-dev) of %1ls, please " 915 L"uninstall it first using Add/Remove Programs in the control panel."; 916 base::string16 name(chrome_dist->GetDisplayName()); 917 base::string16 message( 918 base::StringPrintf(kPleaseUninstallYourChromeMessage, name.c_str())); 919 920 LOG(ERROR) << "Aborting operation: another installation of " << name 921 << " was found, as a last resort (if the product is not present " 922 "in Add/Remove Programs), try executing: " 923 << existing_chrome->uninstall_command().GetCommandLineString(); 924 MessageBox(NULL, message.c_str(), NULL, MB_ICONERROR); 925 return installer::INSTALL_FAILED; 926 } 927 928 base::FilePath chrome_exe( 929 cmd_line.GetSwitchValuePath(installer::switches::kRegisterDevChrome)); 930 if (chrome_exe.empty()) 931 chrome_exe = setup_exe.DirName().Append(installer::kChromeExe); 932 if (!chrome_exe.IsAbsolute()) 933 chrome_exe = base::MakeAbsoluteFilePath(chrome_exe); 934 935 installer::InstallStatus status = installer::FIRST_INSTALL_SUCCESS; 936 if (base::PathExists(chrome_exe)) { 937 Product chrome(chrome_dist); 938 939 // Create the Start menu shortcut and pin it to the taskbar. 940 ShellUtil::ShortcutProperties shortcut_properties(ShellUtil::CURRENT_USER); 941 chrome.AddDefaultShortcutProperties(chrome_exe, &shortcut_properties); 942 shortcut_properties.set_dual_mode(true); 943 shortcut_properties.set_pin_to_taskbar(true); 944 ShellUtil::CreateOrUpdateShortcut( 945 ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR, chrome_dist, 946 shortcut_properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS); 947 948 // Register Chrome at user-level and make it default. 949 scoped_ptr<WorkItemList> delegate_execute_list( 950 WorkItem::CreateWorkItemList()); 951 installer::AddDelegateExecuteWorkItems( 952 installer_state, chrome_exe.DirName(), Version(), chrome, 953 delegate_execute_list.get()); 954 delegate_execute_list->Do(); 955 if (ShellUtil::CanMakeChromeDefaultUnattended()) { 956 ShellUtil::MakeChromeDefault( 957 chrome_dist, ShellUtil::CURRENT_USER, chrome_exe.value(), true); 958 } else { 959 ShellUtil::ShowMakeChromeDefaultSystemUI(chrome_dist, chrome_exe.value()); 960 } 961 } else { 962 LOG(ERROR) << "Path not found: " << chrome_exe.value(); 963 status = installer::INSTALL_FAILED; 964 } 965 return status; 966} 967 968// This method processes any command line options that make setup.exe do 969// various tasks other than installation (renaming chrome.exe, showing eula 970// among others). This function returns true if any such command line option 971// has been found and processed (so setup.exe should exit at that point). 972bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, 973 const base::FilePath& setup_exe, 974 const CommandLine& cmd_line, 975 InstallerState* installer_state, 976 int* exit_code) { 977 // TODO(gab): Add a local |status| variable which each block below sets; 978 // only determine the |exit_code| from |status| at the end (this will allow 979 // this method to validate that 980 // (!handled || status != installer::UNKNOWN_STATUS)). 981 bool handled = true; 982 // TODO(tommi): Split these checks up into functions and use a data driven 983 // map of switch->function. 984 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { 985 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; 986 // If --update-setup-exe command line option is given, we apply the given 987 // patch to current exe, and store the resulting binary in the path 988 // specified by --new-setup-exe. But we need to first unpack the file 989 // given in --update-setup-exe. 990 base::ScopedTempDir temp_path; 991 if (!temp_path.CreateUniqueTempDir()) { 992 PLOG(ERROR) << "Could not create temporary path."; 993 } else { 994 base::FilePath compressed_archive(cmd_line.GetSwitchValuePath( 995 installer::switches::kUpdateSetupExe)); 996 VLOG(1) << "Opening archive " << compressed_archive.value(); 997 if (installer::ArchivePatchHelper::UncompressAndPatch( 998 temp_path.path(), 999 compressed_archive, 1000 setup_exe, 1001 cmd_line.GetSwitchValuePath(installer::switches::kNewSetupExe))) { 1002 status = installer::NEW_VERSION_UPDATED; 1003 } 1004 if (!temp_path.Delete()) { 1005 // PLOG would be nice, but Delete() doesn't leave a meaningful value in 1006 // the Windows last-error code. 1007 LOG(WARNING) << "Scheduling temporary path " << temp_path.path().value() 1008 << " for deletion at reboot."; 1009 ScheduleDirectoryForDeletion(temp_path.path()); 1010 } 1011 } 1012 1013 *exit_code = InstallUtil::GetInstallReturnCode(status); 1014 if (*exit_code) { 1015 LOG(WARNING) << "setup.exe patching failed."; 1016 installer_state->WriteInstallerResult( 1017 status, IDS_SETUP_PATCH_FAILED_BASE, NULL); 1018 } 1019 // We will be exiting normally, so clear the stage indicator. 1020 installer_state->UpdateStage(installer::NO_STAGE); 1021 } else if (cmd_line.HasSwitch(installer::switches::kShowEula)) { 1022 // Check if we need to show the EULA. If it is passed as a command line 1023 // then the dialog is shown and regardless of the outcome setup exits here. 1024 base::string16 inner_frame = 1025 cmd_line.GetSwitchValueNative(installer::switches::kShowEula); 1026 *exit_code = ShowEULADialog(inner_frame); 1027 1028 if (installer::EULA_REJECTED != *exit_code) { 1029 if (GoogleUpdateSettings::SetEULAConsent( 1030 original_state, BrowserDistribution::GetDistribution(), true)) { 1031 CreateEULASentinel(BrowserDistribution::GetDistribution()); 1032 } 1033 // For a metro-originated launch, we now need to launch back into metro. 1034 if (cmd_line.HasSwitch(installer::switches::kShowEulaForMetro)) 1035 ActivateMetroChrome(); 1036 } 1037 } else if (cmd_line.HasSwitch(installer::switches::kConfigureUserSettings)) { 1038 // NOTE: Should the work done here, on kConfigureUserSettings, change: 1039 // kActiveSetupVersion in install_worker.cc needs to be increased for Active 1040 // Setup to invoke this again for all users of this install. 1041 const Product* chrome_install = 1042 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1043 installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; 1044 if (chrome_install && installer_state->system_install()) { 1045 bool force = 1046 cmd_line.HasSwitch(installer::switches::kForceConfigureUserSettings); 1047 installer::HandleActiveSetupForBrowser(installer_state->target_path(), 1048 *chrome_install, force); 1049 status = installer::INSTALL_REPAIRED; 1050 } else { 1051 LOG(DFATAL) << "chrome_install:" << chrome_install 1052 << ", system_install:" << installer_state->system_install(); 1053 } 1054 *exit_code = InstallUtil::GetInstallReturnCode(status); 1055 } else if (cmd_line.HasSwitch(installer::switches::kRegisterDevChrome)) { 1056 installer::InstallStatus status = RegisterDevChrome( 1057 original_state, *installer_state, setup_exe, cmd_line); 1058 *exit_code = InstallUtil::GetInstallReturnCode(status); 1059 } else if (cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser)) { 1060 installer::InstallStatus status = installer::UNKNOWN_STATUS; 1061 const Product* chrome_install = 1062 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1063 if (chrome_install) { 1064 // If --register-chrome-browser option is specified, register all 1065 // Chrome protocol/file associations, as well as register it as a valid 1066 // browser for Start Menu->Internet shortcut. This switch will also 1067 // register Chrome as a valid handler for a set of URL protocols that 1068 // Chrome may become the default handler for, either by the user marking 1069 // Chrome as the default browser, through the Windows Default Programs 1070 // control panel settings, or through website use of 1071 // registerProtocolHandler. These protocols are found in 1072 // ShellUtil::kPotentialProtocolAssociations. 1073 // The --register-url-protocol will additionally register Chrome as a 1074 // potential handler for the supplied protocol, and is used if a website 1075 // registers a handler for a protocol not found in 1076 // ShellUtil::kPotentialProtocolAssociations. 1077 // These options should only be used when setup.exe is launched with admin 1078 // rights. We do not make any user specific changes with this option. 1079 DCHECK(IsUserAnAdmin()); 1080 base::string16 chrome_exe(cmd_line.GetSwitchValueNative( 1081 installer::switches::kRegisterChromeBrowser)); 1082 base::string16 suffix; 1083 if (cmd_line.HasSwitch( 1084 installer::switches::kRegisterChromeBrowserSuffix)) { 1085 suffix = cmd_line.GetSwitchValueNative( 1086 installer::switches::kRegisterChromeBrowserSuffix); 1087 } 1088 if (cmd_line.HasSwitch(installer::switches::kRegisterURLProtocol)) { 1089 base::string16 protocol = cmd_line.GetSwitchValueNative( 1090 installer::switches::kRegisterURLProtocol); 1091 // ShellUtil::RegisterChromeForProtocol performs all registration 1092 // done by ShellUtil::RegisterChromeBrowser, as well as registering 1093 // with Windows as capable of handling the supplied protocol. 1094 if (ShellUtil::RegisterChromeForProtocol( 1095 chrome_install->distribution(), chrome_exe, suffix, protocol, 1096 false)) 1097 status = installer::IN_USE_UPDATED; 1098 } else { 1099 if (ShellUtil::RegisterChromeBrowser(chrome_install->distribution(), 1100 chrome_exe, suffix, false)) 1101 status = installer::IN_USE_UPDATED; 1102 } 1103 } else { 1104 LOG(DFATAL) << "Can't register browser - Chrome distribution not found"; 1105 } 1106 *exit_code = InstallUtil::GetInstallReturnCode(status); 1107 } else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) { 1108 // If --rename-chrome-exe is specified, we want to rename the executables 1109 // and exit. 1110 *exit_code = RenameChromeExecutables(original_state, installer_state); 1111 } else if (cmd_line.HasSwitch( 1112 installer::switches::kRemoveChromeRegistration)) { 1113 // This is almost reverse of --register-chrome-browser option above. 1114 // Here we delete Chrome browser registration. This option should only 1115 // be used when setup.exe is launched with admin rights. We do not 1116 // make any user specific changes in this option. 1117 base::string16 suffix; 1118 if (cmd_line.HasSwitch( 1119 installer::switches::kRegisterChromeBrowserSuffix)) { 1120 suffix = cmd_line.GetSwitchValueNative( 1121 installer::switches::kRegisterChromeBrowserSuffix); 1122 } 1123 installer::InstallStatus tmp = installer::UNKNOWN_STATUS; 1124 const Product* chrome_install = 1125 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1126 DCHECK(chrome_install); 1127 if (chrome_install) { 1128 installer::DeleteChromeRegistrationKeys(*installer_state, 1129 chrome_install->distribution(), HKEY_LOCAL_MACHINE, suffix, &tmp); 1130 } 1131 *exit_code = tmp; 1132 } else if (cmd_line.HasSwitch(installer::switches::kOnOsUpgrade)) { 1133 const Product* chrome_install = 1134 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER); 1135 installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION; 1136 if (chrome_install) { 1137 installer::HandleOsUpgradeForBrowser(*installer_state, 1138 *chrome_install); 1139 status = installer::INSTALL_REPAIRED; 1140 } else { 1141 LOG(DFATAL) << "Chrome product not found."; 1142 } 1143 *exit_code = InstallUtil::GetInstallReturnCode(status); 1144 } else if (cmd_line.HasSwitch(installer::switches::kQueryEULAAcceptance)) { 1145 *exit_code = installer::IsEULAAccepted(installer_state->system_install()); 1146 } else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) { 1147 // Launch the inactive user toast experiment. 1148 int flavor = -1; 1149 base::StringToInt(cmd_line.GetSwitchValueNative( 1150 installer::switches::kInactiveUserToast), &flavor); 1151 std::string experiment_group = 1152 cmd_line.GetSwitchValueASCII(installer::switches::kExperimentGroup); 1153 DCHECK_NE(-1, flavor); 1154 if (flavor == -1) { 1155 *exit_code = installer::UNKNOWN_STATUS; 1156 } else { 1157 // This code is called (via setup.exe relaunch) only if a product is known 1158 // to run user experiments, so no check is required. 1159 const Products& products = installer_state->products(); 1160 for (Products::const_iterator it = products.begin(); it < products.end(); 1161 ++it) { 1162 const Product& product = **it; 1163 installer::InactiveUserToastExperiment( 1164 flavor, base::ASCIIToUTF16(experiment_group), product, 1165 installer_state->target_path()); 1166 } 1167 } 1168 } else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { 1169 const Products& products = installer_state->products(); 1170 for (Products::const_iterator it = products.begin(); it < products.end(); 1171 ++it) { 1172 const Product& product = **it; 1173 BrowserDistribution* browser_dist = product.distribution(); 1174 // We started as system-level and have been re-launched as user level 1175 // to continue with the toast experiment. 1176 Version installed_version; 1177 InstallUtil::GetChromeVersion(browser_dist, true, &installed_version); 1178 if (!installed_version.IsValid()) { 1179 LOG(ERROR) << "No installation of " 1180 << browser_dist->GetDisplayName() 1181 << " found for system-level toast."; 1182 } else { 1183 product.LaunchUserExperiment( 1184 setup_exe, installer::REENTRY_SYS_UPDATE, true); 1185 } 1186 } 1187 } else if (cmd_line.HasSwitch(installer::switches::kPatch)) { 1188 const std::string patch_type_str( 1189 cmd_line.GetSwitchValueASCII(installer::switches::kPatch)); 1190 const base::FilePath input_file( 1191 cmd_line.GetSwitchValuePath(installer::switches::kInputFile)); 1192 const base::FilePath patch_file( 1193 cmd_line.GetSwitchValuePath(installer::switches::kPatchFile)); 1194 const base::FilePath output_file( 1195 cmd_line.GetSwitchValuePath(installer::switches::kOutputFile)); 1196 1197 if (patch_type_str == installer::kCourgette) { 1198 *exit_code = installer::CourgettePatchFiles(input_file, 1199 patch_file, 1200 output_file); 1201 } else if (patch_type_str == installer::kBsdiff) { 1202 *exit_code = installer::BsdiffPatchFiles(input_file, 1203 patch_file, 1204 output_file); 1205 } else { 1206 *exit_code = installer::PATCH_INVALID_ARGUMENTS; 1207 } 1208 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { 1209 // setup.exe has been asked to attempt to reenable updates for Chrome. 1210 // Figure out whether we should do so for the multi binaries or the main 1211 // Chrome product. 1212 BrowserDistribution::Type dist_type = BrowserDistribution::CHROME_BROWSER; 1213 if (installer_state->is_multi_install()) 1214 dist_type = BrowserDistribution::CHROME_BINARIES; 1215 1216 BrowserDistribution* dist = 1217 BrowserDistribution::GetSpecificDistribution(dist_type); 1218 bool updates_enabled = 1219 GoogleUpdateSettings::ReenableAutoupdatesForApp(dist->GetAppGuid()); 1220 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : 1221 installer::REENABLE_UPDATES_FAILED; 1222 } else { 1223 handled = false; 1224 } 1225 1226 return handled; 1227} 1228 1229bool ShowRebootDialog() { 1230 // Get a token for this process. 1231 HANDLE token; 1232 if (!OpenProcessToken(GetCurrentProcess(), 1233 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 1234 &token)) { 1235 LOG(ERROR) << "Failed to open token."; 1236 return false; 1237 } 1238 1239 // Use a ScopedHandle to keep track of and eventually close our handle. 1240 // TODO(robertshield): Add a Receive() method to base's ScopedHandle. 1241 base::win::ScopedHandle scoped_handle(token); 1242 1243 // Get the LUID for the shutdown privilege. 1244 TOKEN_PRIVILEGES tkp = {0}; 1245 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 1246 tkp.PrivilegeCount = 1; 1247 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 1248 1249 // Get the shutdown privilege for this process. 1250 AdjustTokenPrivileges(token, FALSE, &tkp, 0, 1251 reinterpret_cast<PTOKEN_PRIVILEGES>(NULL), 0); 1252 if (GetLastError() != ERROR_SUCCESS) { 1253 LOG(ERROR) << "Unable to get shutdown privileges."; 1254 return false; 1255 } 1256 1257 // Popup a dialog that will prompt to reboot using the default system message. 1258 // TODO(robertshield): Add a localized, more specific string to the prompt. 1259 RestartDialog(NULL, NULL, EWX_REBOOT | EWX_FORCEIFHUNG); 1260 return true; 1261} 1262 1263// Returns the Custom information for the client identified by the exe path 1264// passed in. This information is used for crash reporting. 1265google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { 1266 base::string16 product; 1267 base::string16 version; 1268 scoped_ptr<FileVersionInfo> version_info( 1269 FileVersionInfo::CreateFileVersionInfo(base::FilePath(exe_path))); 1270 if (version_info.get()) { 1271 version = version_info->product_version(); 1272 product = version_info->product_short_name(); 1273 } 1274 1275 if (version.empty()) 1276 version = L"0.1.0.0"; 1277 1278 if (product.empty()) 1279 product = L"Chrome Installer"; 1280 1281 static google_breakpad::CustomInfoEntry ver_entry(L"ver", version.c_str()); 1282 static google_breakpad::CustomInfoEntry prod_entry(L"prod", product.c_str()); 1283 static google_breakpad::CustomInfoEntry plat_entry(L"plat", L"Win32"); 1284 static google_breakpad::CustomInfoEntry type_entry(L"ptype", 1285 L"Chrome Installer"); 1286 static google_breakpad::CustomInfoEntry entries[] = { 1287 ver_entry, prod_entry, plat_entry, type_entry }; 1288 static google_breakpad::CustomClientInfo custom_info = { 1289 entries, arraysize(entries) }; 1290 return &custom_info; 1291} 1292 1293// Initialize crash reporting for this process. This involves connecting to 1294// breakpad, etc. 1295scoped_ptr<google_breakpad::ExceptionHandler> InitializeCrashReporting( 1296 bool system_install) { 1297 // Only report crashes if the user allows it. 1298 if (!GoogleUpdateSettings::GetCollectStatsConsent()) 1299 return scoped_ptr<google_breakpad::ExceptionHandler>(); 1300 1301 // Get the alternate dump directory. We use the temp path. 1302 base::FilePath temp_directory; 1303 if (!base::GetTempDir(&temp_directory) || temp_directory.empty()) 1304 return scoped_ptr<google_breakpad::ExceptionHandler>(); 1305 1306 wchar_t exe_path[MAX_PATH * 2] = {0}; 1307 GetModuleFileName(NULL, exe_path, arraysize(exe_path)); 1308 1309 // Build the pipe name. It can be either: 1310 // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18" 1311 // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>" 1312 base::string16 user_sid = kSystemPrincipalSid; 1313 1314 if (!system_install) { 1315 if (!base::win::GetUserSidString(&user_sid)) { 1316 return scoped_ptr<google_breakpad::ExceptionHandler>(); 1317 } 1318 } 1319 1320 base::string16 pipe_name = kGoogleUpdatePipeName; 1321 pipe_name += user_sid; 1322 1323 return scoped_ptr<google_breakpad::ExceptionHandler>( 1324 new google_breakpad::ExceptionHandler( 1325 temp_directory.value(), NULL, NULL, NULL, 1326 google_breakpad::ExceptionHandler::HANDLER_ALL, kLargerDumpType, 1327 pipe_name.c_str(), GetCustomInfo(exe_path))); 1328} 1329 1330// Uninstalls multi-install Chrome Frame if the current operation is a 1331// multi-install install or update. The operation is performed directly rather 1332// than delegated to the existing install since there is no facility in older 1333// versions of setup.exe to uninstall GCF without touching the binaries. The 1334// binaries will be uninstalled during later processing if they are not in-use 1335// (see UninstallBinariesIfUnused). |original_state| and |installer_state| are 1336// updated to reflect the state of the world following the operation. 1337void UninstallMultiChromeFrameIfPresent(const CommandLine& cmd_line, 1338 const MasterPreferences& prefs, 1339 InstallationState* original_state, 1340 InstallerState* installer_state) { 1341 // Early exit if not installing or updating multi-install product(s). 1342 if (installer_state->operation() != InstallerState::MULTI_INSTALL && 1343 installer_state->operation() != InstallerState::MULTI_UPDATE) { 1344 return; 1345 } 1346 1347 // Early exit if Chrome Frame is not present as multi-install. 1348 const ProductState* chrome_frame_state = 1349 original_state->GetProductState(installer_state->system_install(), 1350 BrowserDistribution::CHROME_FRAME); 1351 if (!chrome_frame_state || !chrome_frame_state->is_multi_install()) 1352 return; 1353 1354 LOG(INFO) << "Uninstalling multi-install Chrome Frame."; 1355 installer_state->UpdateStage(installer::UNINSTALLING_CHROME_FRAME); 1356 1357 // Uninstall Chrome Frame without touching the multi-install binaries. 1358 // Simulate the uninstall as coming from the installed version. 1359 const CommandLine& uninstall_cmd(chrome_frame_state->uninstall_command()); 1360 MasterPreferences uninstall_prefs(uninstall_cmd); 1361 InstallerState uninstall_state; 1362 uninstall_state.Initialize(uninstall_cmd, uninstall_prefs, *original_state); 1363 // Post M32, uninstall_prefs and uninstall_state won't have Chrome Frame in 1364 // them since they've lost the power to do Chrome Frame installs. 1365 const Product* chrome_frame_product = uninstall_state.AddProductFromState( 1366 BrowserDistribution::CHROME_FRAME, *chrome_frame_state); 1367 if (chrome_frame_product) { 1368 // No shared state should be left behind. 1369 const bool remove_all = true; 1370 // Don't accept no for an answer. 1371 const bool force_uninstall = true; 1372 installer::InstallStatus uninstall_status = 1373 installer::UninstallProduct(*original_state, uninstall_state, 1374 uninstall_cmd.GetProgram(), 1375 *chrome_frame_product, remove_all, 1376 force_uninstall, cmd_line); 1377 1378 VLOG(1) << "Uninstallation of Chrome Frame returned status " 1379 << uninstall_status; 1380 } else { 1381 LOG(ERROR) << "Chrome Frame not found for uninstall."; 1382 } 1383 1384 // Refresh state for the continuation of the original install/update. 1385 original_state->Initialize(); 1386 installer_state->Initialize(cmd_line, prefs, *original_state); 1387} 1388 1389} // namespace 1390 1391namespace installer { 1392 1393InstallStatus InstallProductsHelper( 1394 const InstallationState& original_state, 1395 const base::FilePath& setup_exe, 1396 const CommandLine& cmd_line, 1397 const MasterPreferences& prefs, 1398 const InstallerState& installer_state, 1399 base::FilePath* installer_directory, 1400 ArchiveType* archive_type, 1401 bool* delegated_to_existing) { 1402 DCHECK(archive_type); 1403 DCHECK(delegated_to_existing); 1404 const bool system_install = installer_state.system_install(); 1405 InstallStatus install_status = UNKNOWN_STATUS; 1406 1407 // Drop to background processing mode if the process was started below the 1408 // normal process priority class. 1409 bool entered_background_mode = AdjustProcessPriority(); 1410 VLOG_IF(1, entered_background_mode) << "Entered background processing mode."; 1411 1412 // Create a temp folder where we will unpack Chrome archive. If it fails, 1413 // then we are doomed, so return immediately and no cleanup is required. 1414 SelfCleaningTempDir temp_path; 1415 base::FilePath unpack_path; 1416 if (!CreateTemporaryAndUnpackDirectories(installer_state, &temp_path, 1417 &unpack_path)) { 1418 installer_state.WriteInstallerResult(TEMP_DIR_FAILED, 1419 IDS_INSTALL_TEMP_DIR_FAILED_BASE, 1420 NULL); 1421 return TEMP_DIR_FAILED; 1422 } 1423 1424 // Uncompress and optionally patch the archive if an uncompressed archive was 1425 // not specified on the command line and a compressed archive is found. 1426 *archive_type = UNKNOWN_ARCHIVE_TYPE; 1427 base::FilePath uncompressed_archive(cmd_line.GetSwitchValuePath( 1428 switches::kUncompressedArchive)); 1429 if (uncompressed_archive.empty()) { 1430 scoped_ptr<ArchivePatchHelper> archive_helper( 1431 CreateChromeArchiveHelper(setup_exe, cmd_line, installer_state, 1432 unpack_path)); 1433 if (archive_helper) { 1434 VLOG(1) << "Installing Chrome from compressed archive " 1435 << archive_helper->compressed_archive().value(); 1436 if (!UncompressAndPatchChromeArchive(original_state, 1437 installer_state, 1438 archive_helper.get(), 1439 archive_type, 1440 &install_status)) { 1441 DCHECK_NE(install_status, UNKNOWN_STATUS); 1442 return install_status; 1443 } 1444 uncompressed_archive = archive_helper->target(); 1445 DCHECK(!uncompressed_archive.empty()); 1446 } 1447 } 1448 1449 // Check for an uncompressed archive alongside the current executable if one 1450 // was not given or generated. 1451 if (uncompressed_archive.empty()) 1452 uncompressed_archive = setup_exe.DirName().Append(kChromeArchive); 1453 1454 if (*archive_type == UNKNOWN_ARCHIVE_TYPE) { 1455 // An archive was not uncompressed or patched above. 1456 if (uncompressed_archive.empty() || 1457 !base::PathExists(uncompressed_archive)) { 1458 LOG(ERROR) << "Cannot install Chrome without an uncompressed archive."; 1459 installer_state.WriteInstallerResult( 1460 INVALID_ARCHIVE, IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); 1461 return INVALID_ARCHIVE; 1462 } 1463 *archive_type = FULL_ARCHIVE_TYPE; 1464 } 1465 1466 // Unpack the uncompressed archive. 1467 if (LzmaUtil::UnPackArchive(uncompressed_archive.value(), 1468 unpack_path.value(), 1469 NULL)) { 1470 installer_state.WriteInstallerResult( 1471 UNCOMPRESSION_FAILED, 1472 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, 1473 NULL); 1474 return UNCOMPRESSION_FAILED; 1475 } 1476 1477 VLOG(1) << "unpacked to " << unpack_path.value(); 1478 base::FilePath src_path( 1479 unpack_path.Append(kInstallSourceChromeDir)); 1480 scoped_ptr<Version> 1481 installer_version(GetMaxVersionFromArchiveDir(src_path)); 1482 if (!installer_version.get()) { 1483 LOG(ERROR) << "Did not find any valid version in installer."; 1484 install_status = INVALID_ARCHIVE; 1485 installer_state.WriteInstallerResult(install_status, 1486 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); 1487 } else { 1488 VLOG(1) << "version to install: " << installer_version->GetString(); 1489 bool proceed_with_installation = true; 1490 1491 if (installer_state.operation() == InstallerState::MULTI_INSTALL) { 1492 // This is a new install of a multi-install product. Rather than give up 1493 // in case a higher version of the binaries (including a single-install 1494 // of Chrome, which can safely be migrated to multi-install by way of 1495 // CheckMultiInstallConditions) is already installed, delegate to the 1496 // installed setup.exe to install the product at hand. 1497 base::FilePath existing_setup_exe; 1498 if (GetExistingHigherInstaller(original_state, system_install, 1499 *installer_version, &existing_setup_exe)) { 1500 VLOG(1) << "Deferring to existing installer."; 1501 installer_state.UpdateStage(DEFERRING_TO_HIGHER_VERSION); 1502 if (DeferToExistingInstall(existing_setup_exe, cmd_line, 1503 installer_state, temp_path.path(), 1504 &install_status)) { 1505 *delegated_to_existing = true; 1506 return install_status; 1507 } 1508 } 1509 } 1510 1511 uint32 higher_products = 0; 1512 COMPILE_ASSERT( 1513 sizeof(higher_products) * 8 > BrowserDistribution::NUM_TYPES, 1514 too_many_distribution_types_); 1515 const Products& products = installer_state.products(); 1516 for (Products::const_iterator it = products.begin(); it < products.end(); 1517 ++it) { 1518 const Product& product = **it; 1519 const ProductState* product_state = 1520 original_state.GetProductState(system_install, 1521 product.distribution()->GetType()); 1522 if (product_state != NULL && 1523 (product_state->version().CompareTo(*installer_version) > 0)) { 1524 LOG(ERROR) << "Higher version of " 1525 << product.distribution()->GetDisplayName() 1526 << " is already installed."; 1527 higher_products |= (1 << product.distribution()->GetType()); 1528 } 1529 } 1530 1531 if (higher_products != 0) { 1532 COMPILE_ASSERT(BrowserDistribution::NUM_TYPES == 4, 1533 add_support_for_new_products_here_); 1534 const uint32 kBrowserBit = 1 << BrowserDistribution::CHROME_BROWSER; 1535 const uint32 kAppHostBit = 1 << BrowserDistribution::CHROME_APP_HOST; 1536 int message_id = 0; 1537 1538 proceed_with_installation = false; 1539 install_status = HIGHER_VERSION_EXISTS; 1540 switch (higher_products) { 1541 case kBrowserBit: 1542 message_id = IDS_INSTALL_HIGHER_VERSION_BASE; 1543 break; 1544 default: 1545 message_id = IDS_INSTALL_HIGHER_VERSION_APP_LAUNCHER_BASE; 1546 break; 1547 } 1548 1549 installer_state.WriteInstallerResult(install_status, message_id, NULL); 1550 } 1551 1552 proceed_with_installation = 1553 proceed_with_installation && 1554 CheckGroupPolicySettings(original_state, installer_state, 1555 *installer_version, &install_status); 1556 1557 if (proceed_with_installation) { 1558 // If Google Update is absent at user-level, install it using the 1559 // Google Update installer from an existing system-level installation. 1560 // This is for quick-enable App Host install from a system-level 1561 // Chrome Binaries installation. 1562 if (!system_install && installer_state.ensure_google_update_present()) { 1563 if (!google_update::EnsureUserLevelGoogleUpdatePresent()) { 1564 LOG(ERROR) << "Failed to install Google Update"; 1565 proceed_with_installation = false; 1566 install_status = INSTALL_OF_GOOGLE_UPDATE_FAILED; 1567 installer_state.WriteInstallerResult(install_status, 0, NULL); 1568 } 1569 } 1570 1571 } 1572 1573 if (proceed_with_installation) { 1574 base::FilePath prefs_source_path(cmd_line.GetSwitchValueNative( 1575 switches::kInstallerData)); 1576 install_status = InstallOrUpdateProduct( 1577 original_state, installer_state, setup_exe, uncompressed_archive, 1578 temp_path.path(), src_path, prefs_source_path, prefs, 1579 *installer_version); 1580 1581 int install_msg_base = IDS_INSTALL_FAILED_BASE; 1582 base::string16 chrome_exe; 1583 base::string16 quoted_chrome_exe; 1584 if (install_status == SAME_VERSION_REPAIR_FAILED) { 1585 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; 1586 } else if (install_status != INSTALL_FAILED) { 1587 if (installer_state.target_path().empty()) { 1588 // If we failed to construct install path, it means the OS call to 1589 // get %ProgramFiles% or %AppData% failed. Report this as failure. 1590 install_msg_base = IDS_INSTALL_OS_ERROR_BASE; 1591 install_status = OS_ERROR; 1592 } else { 1593 chrome_exe = installer_state.target_path().Append(kChromeExe).value(); 1594 quoted_chrome_exe = L"\"" + chrome_exe + L"\""; 1595 install_msg_base = 0; 1596 } 1597 } 1598 1599 installer_state.UpdateStage(FINISHING); 1600 1601 // Only do Chrome-specific stuff (like launching the browser) if 1602 // Chrome was specifically requested (rather than being upgraded as 1603 // part of a multi-install). 1604 const Product* chrome_install = prefs.install_chrome() ? 1605 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER) : 1606 NULL; 1607 1608 bool do_not_register_for_update_launch = false; 1609 if (chrome_install) { 1610 prefs.GetBool(master_preferences::kDoNotRegisterForUpdateLaunch, 1611 &do_not_register_for_update_launch); 1612 } else { 1613 do_not_register_for_update_launch = true; // Never register. 1614 } 1615 1616 bool write_chrome_launch_string = 1617 (!do_not_register_for_update_launch && 1618 install_status != IN_USE_UPDATED); 1619 1620 installer_state.WriteInstallerResult(install_status, install_msg_base, 1621 write_chrome_launch_string ? "ed_chrome_exe : NULL); 1622 1623 if (install_status == FIRST_INSTALL_SUCCESS) { 1624 VLOG(1) << "First install successful."; 1625 if (chrome_install) { 1626 // We never want to launch Chrome in system level install mode. 1627 bool do_not_launch_chrome = false; 1628 prefs.GetBool(master_preferences::kDoNotLaunchChrome, 1629 &do_not_launch_chrome); 1630 if (!system_install && !do_not_launch_chrome) 1631 chrome_install->LaunchChrome(installer_state.target_path()); 1632 } 1633 } else if ((install_status == NEW_VERSION_UPDATED) || 1634 (install_status == IN_USE_UPDATED)) { 1635 const Product* chrome = installer_state.FindProduct( 1636 BrowserDistribution::CHROME_BROWSER); 1637 if (chrome != NULL) { 1638 DCHECK_NE(chrome_exe, base::string16()); 1639 RemoveChromeLegacyRegistryKeys(chrome->distribution(), chrome_exe); 1640 } 1641 } 1642 1643 if (prefs.install_chrome_app_launcher() && 1644 InstallUtil::GetInstallReturnCode(install_status) == 0) { 1645 std::string webstore_item(google_update::GetUntrustedDataValue( 1646 kInstallFromWebstore)); 1647 if (!webstore_item.empty()) { 1648 bool success = InstallFromWebstore(webstore_item); 1649 VLOG_IF(1, !success) << "Failed to launch app installation."; 1650 } 1651 } 1652 } 1653 } 1654 1655 // There might be an experiment (for upgrade usually) that needs to happen. 1656 // An experiment's outcome can include chrome's uninstallation. If that is 1657 // the case we would not do that directly at this point but in another 1658 // instance of setup.exe 1659 // 1660 // There is another way to reach this same function if this is a system 1661 // level install. See HandleNonInstallCmdLineOptions(). 1662 { 1663 // If installation failed, use the path to the currently running setup. 1664 // If installation succeeded, use the path to setup in the installer dir. 1665 base::FilePath setup_path(setup_exe); 1666 if (InstallUtil::GetInstallReturnCode(install_status) == 0) { 1667 setup_path = installer_state.GetInstallerDirectory(*installer_version) 1668 .Append(setup_path.BaseName()); 1669 } 1670 const Products& products = installer_state.products(); 1671 for (Products::const_iterator it = products.begin(); it < products.end(); 1672 ++it) { 1673 const Product& product = **it; 1674 product.LaunchUserExperiment(setup_path, install_status, system_install); 1675 } 1676 } 1677 1678 // If installation completed successfully, return the path to the directory 1679 // containing the newly installed setup.exe and uncompressed archive if the 1680 // caller requested it. 1681 if (installer_directory && 1682 InstallUtil::GetInstallReturnCode(install_status) == 0) { 1683 *installer_directory = 1684 installer_state.GetInstallerDirectory(*installer_version); 1685 } 1686 1687 // temp_path's dtor will take care of deleting or scheduling itself for 1688 // deletion at reboot when this scope closes. 1689 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); 1690 1691 return install_status; 1692} 1693 1694} // namespace installer 1695 1696int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, 1697 wchar_t* command_line, int show_command) { 1698 // Check to see if the CPU is supported before doing anything else. There's 1699 // very little than can safely be accomplished if the CPU isn't supported 1700 // since dependent libraries (e.g., base) may use invalid instructions. 1701 if (!installer::IsProcessorSupported()) 1702 return installer::CPU_NOT_SUPPORTED; 1703 1704 // The exit manager is in charge of calling the dtors of singletons. 1705 base::AtExitManager exit_manager; 1706 CommandLine::Init(0, NULL); 1707 1708 // install_util uses chrome paths. 1709 chrome::RegisterPathProvider(); 1710 1711 const MasterPreferences& prefs = MasterPreferences::ForCurrentProcess(); 1712 installer::InitInstallerLogging(prefs); 1713 1714 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); 1715 VLOG(1) << "Command Line: " << cmd_line.GetCommandLineString(); 1716 1717 VLOG(1) << "multi install is " << prefs.is_multi_install(); 1718 bool system_install = false; 1719 prefs.GetBool(installer::master_preferences::kSystemLevel, &system_install); 1720 VLOG(1) << "system install is " << system_install; 1721 1722 scoped_ptr<google_breakpad::ExceptionHandler> breakpad( 1723 InitializeCrashReporting(system_install)); 1724 1725 InstallationState original_state; 1726 original_state.Initialize(); 1727 1728 InstallerState installer_state; 1729 installer_state.Initialize(cmd_line, prefs, original_state); 1730 const bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall); 1731 1732 // Check to make sure current system is WinXP or later. If not, log 1733 // error message and get out. 1734 if (!InstallUtil::IsOSSupported()) { 1735 LOG(ERROR) << "Chrome only supports Windows XP or later."; 1736 installer_state.WriteInstallerResult( 1737 installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, NULL); 1738 return installer::OS_NOT_SUPPORTED; 1739 } 1740 1741 // Initialize COM for use later. 1742 base::win::ScopedCOMInitializer com_initializer; 1743 if (!com_initializer.succeeded()) { 1744 installer_state.WriteInstallerResult( 1745 installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL); 1746 return installer::OS_ERROR; 1747 } 1748 1749 // Some command line options don't work with SxS install/uninstall 1750 if (InstallUtil::IsChromeSxSProcess()) { 1751 if (system_install || 1752 prefs.is_multi_install() || 1753 cmd_line.HasSwitch(installer::switches::kForceUninstall) || 1754 cmd_line.HasSwitch(installer::switches::kMakeChromeDefault) || 1755 cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser) || 1756 cmd_line.HasSwitch(installer::switches::kRemoveChromeRegistration) || 1757 cmd_line.HasSwitch(installer::switches::kInactiveUserToast) || 1758 cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { 1759 return installer::SXS_OPTION_NOT_SUPPORTED; 1760 } 1761 } 1762 1763 // Some command line options are no longer supported and must error out. 1764 if (installer::ContainsUnsupportedSwitch(cmd_line)) 1765 return installer::UNSUPPORTED_OPTION; 1766 1767 // A variety of installer operations require the path to the current 1768 // executable. Get it once here for use throughout these operations. Note that 1769 // the path service is the authoritative source for this path. One might think 1770 // that CommandLine::GetProgram would suffice, but it won't since 1771 // CreateProcess may have been called with a command line that is somewhat 1772 // ambiguous (e.g., an unquoted path with spaces, or a path lacking the file 1773 // extension), in which case CommandLineToArgv will not yield an argv with the 1774 // true path to the program at position 0. 1775 base::FilePath setup_exe; 1776 if (!PathService::Get(base::FILE_EXE, &setup_exe)) { 1777 NOTREACHED(); 1778 return installer::OS_ERROR; 1779 } 1780 1781 int exit_code = 0; 1782 if (HandleNonInstallCmdLineOptions( 1783 original_state, setup_exe, cmd_line, &installer_state, &exit_code)) { 1784 return exit_code; 1785 } 1786 1787 if (system_install && !IsUserAnAdmin()) { 1788 if (base::win::GetVersion() >= base::win::VERSION_VISTA && 1789 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { 1790 CommandLine new_cmd(CommandLine::NO_PROGRAM); 1791 new_cmd.AppendArguments(cmd_line, true); 1792 // Append --run-as-admin flag to let the new instance of setup.exe know 1793 // that we already tried to launch ourselves as admin. 1794 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); 1795 // If system_install became true due to an environment variable, append 1796 // it to the command line here since env vars may not propagate past the 1797 // elevation. 1798 if (!new_cmd.HasSwitch(installer::switches::kSystemLevel)) 1799 new_cmd.AppendSwitch(installer::switches::kSystemLevel); 1800 1801 DWORD exit_code = installer::UNKNOWN_STATUS; 1802 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); 1803 return exit_code; 1804 } else { 1805 LOG(ERROR) << "Non admin user can not install system level Chrome."; 1806 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS, 1807 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); 1808 return installer::INSUFFICIENT_RIGHTS; 1809 } 1810 } 1811 1812 UninstallMultiChromeFrameIfPresent(cmd_line, prefs, 1813 &original_state, &installer_state); 1814 1815 base::FilePath installer_directory; 1816 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; 1817 // If --uninstall option is given, uninstall the identified product(s) 1818 if (is_uninstall) { 1819 install_status = 1820 UninstallProducts(original_state, installer_state, setup_exe, cmd_line); 1821 } else { 1822 // If --uninstall option is not specified, we assume it is install case. 1823 install_status = 1824 InstallProducts(original_state, setup_exe, cmd_line, prefs, 1825 &installer_state, &installer_directory); 1826 } 1827 1828 // Validate that the machine is now in a good state following the operation. 1829 // TODO(grt): change this to log at DFATAL once we're convinced that the 1830 // validator handles all cases properly. 1831 InstallationValidator::InstallationType installation_type = 1832 InstallationValidator::NO_PRODUCTS; 1833 LOG_IF(ERROR, 1834 !InstallationValidator::ValidateInstallationType(system_install, 1835 &installation_type)); 1836 1837 int return_code = 0; 1838 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will 1839 // rollback the action. If we're uninstalling we want to avoid this, so always 1840 // report success, squashing any more informative return codes. 1841 if (!(installer_state.is_msi() && is_uninstall)) { 1842 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT 1843 // to pass through, since this is only returned on uninstall which is 1844 // never invoked directly by Google Update. 1845 return_code = InstallUtil::GetInstallReturnCode(install_status); 1846 } 1847 1848 VLOG(1) << "Installation complete, returning: " << return_code; 1849 1850 return return_code; 1851} 1852