1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/installer/setup/chrome_frame_quick_enable.h" 6 7 #include <windows.h> 8 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/logging.h" 11 #include "base/strings/string_util.h" 12 #include "base/win/registry.h" 13 #include "chrome/installer/setup/install_worker.h" 14 #include "chrome/installer/util/google_update_constants.h" 15 #include "chrome/installer/util/google_update_settings.h" 16 #include "chrome/installer/util/install_util.h" 17 #include "chrome/installer/util/installation_state.h" 18 #include "chrome/installer/util/installer_state.h" 19 #include "chrome/installer/util/product.h" 20 #include "chrome/installer/util/work_item.h" 21 #include "chrome/installer/util/work_item_list.h" 22 23 using base::win::RegKey; 24 25 namespace installer { 26 27 namespace { 28 29 InstallStatus CheckQuickEnablePreconditions( 30 const InstallationState& machine_state, 31 const InstallerState& installer_state) { 32 // Make sure Chrome is multi-installed. 33 const ProductState* chrome_state = 34 machine_state.GetProductState(installer_state.system_install(), 35 BrowserDistribution::CHROME_BROWSER); 36 if (chrome_state == NULL) { 37 LOG(ERROR) << "Chrome Frame quick enable requires Chrome to be installed."; 38 return CHROME_NOT_INSTALLED; 39 } else if (!chrome_state->is_multi_install()) { 40 LOG(ERROR) << "Chrome Frame quick enable requires multi-install of Chrome."; 41 return NON_MULTI_INSTALLATION_EXISTS; 42 } 43 44 // Chrome Frame must not be installed (ready-mode doesn't count). 45 const ProductState* cf_state = 46 machine_state.GetProductState(installer_state.system_install(), 47 BrowserDistribution::CHROME_FRAME); 48 // Make sure we check both user and system installations. 49 if (!cf_state) { 50 cf_state = machine_state.GetProductState(!installer_state.system_install(), 51 BrowserDistribution::CHROME_FRAME); 52 } 53 54 if (cf_state != NULL && 55 !cf_state->uninstall_command().HasSwitch( 56 switches::kChromeFrameReadyMode)) { 57 LOG(ERROR) << "Chrome Frame already installed."; 58 return installer_state.system_install() ? 59 SYSTEM_LEVEL_INSTALL_EXISTS : USER_LEVEL_INSTALL_EXISTS; 60 } 61 62 return FIRST_INSTALL_SUCCESS; 63 } 64 65 } // end namespace 66 67 InstallStatus ChromeFrameQuickEnable(const InstallationState& machine_state, 68 InstallerState* installer_state) { 69 DCHECK(installer_state); 70 VLOG(1) << "Chrome Frame Quick Enable"; 71 InstallStatus status = CheckQuickEnablePreconditions(machine_state, 72 *installer_state); 73 74 if (status == FIRST_INSTALL_SUCCESS) { 75 scoped_ptr<Product> multi_cf(new Product( 76 BrowserDistribution::GetSpecificDistribution( 77 BrowserDistribution::CHROME_FRAME))); 78 multi_cf->SetOption(installer::kOptionMultiInstall, true); 79 Product* cf = installer_state->AddProduct(&multi_cf); 80 if (!cf) { 81 LOG(ERROR) << "AddProduct failed"; 82 status = INSTALL_FAILED; 83 } else { 84 base::ScopedTempDir temp_path; 85 if (!temp_path.CreateUniqueTempDir()) { 86 PLOG(ERROR) << "Failed to create Temp directory"; 87 return INSTALL_FAILED; 88 } 89 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); 90 const ProductState* chrome_state = 91 machine_state.GetProductState(installer_state->system_install(), 92 BrowserDistribution::CHROME_BROWSER); 93 DCHECK(chrome_state); // Checked in CheckQuickEnablePreconditions. 94 95 // Temporarily remove Chrome from the product list. 96 // This is so that the operations below do not affect the installation 97 // state of Chrome. 98 installer_state->RemoveProduct( 99 installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER)); 100 101 base::FilePath setup_path(chrome_state->GetSetupPath()); 102 const Version& new_version = chrome_state->version(); 103 104 // This creates the uninstallation entry for GCF. 105 AddUninstallShortcutWorkItems(*installer_state, setup_path, new_version, 106 *cf, item_list.get()); 107 // Always set the "lang" value since quick-enable always happens in the 108 // context of an interactive session with a user. 109 AddVersionKeyWorkItems(installer_state->root_key(), cf->distribution(), 110 new_version, true, item_list.get()); 111 AddChromeFrameWorkItems(machine_state, *installer_state, setup_path, 112 new_version, *cf, item_list.get()); 113 114 const Version* opv = chrome_state->old_version(); 115 AppendPostInstallTasks(*installer_state, setup_path, opv, 116 new_version, temp_path.path(), item_list.get()); 117 118 // Before updating the channel values, add Chrome back to the mix so that 119 // all multi-installed products' channel values get updated. 120 installer_state->AddProductFromState(BrowserDistribution::CHROME_BROWSER, 121 *chrome_state); 122 AddGoogleUpdateWorkItems(machine_state, *installer_state, 123 item_list.get()); 124 125 // Add the items to remove the quick-enable-cf command from the registry. 126 AddQuickEnableChromeFrameWorkItems( 127 *installer_state, machine_state, 128 chrome_state->uninstall_command().GetProgram(), 129 new_version, 130 item_list.get()); 131 132 if (!item_list->Do()) { 133 item_list->Rollback(); 134 status = INSTALL_FAILED; 135 } else { 136 DCHECK_EQ(FIRST_INSTALL_SUCCESS, status); 137 VLOG(1) << "Chrome Frame successfully activated."; 138 } 139 } 140 } 141 142 // If quick-enable succeeded, check to see if the EULA has not yet been 143 // accepted for the binaries. If this is the case, we must also flip the 144 // eulaaccepted bit for them. Otherwise, Google Update would not update 145 // Chrome Frame, and that would be bad. Don't flip the EULA bit for Chrome 146 // itself, as it will show the EULA on first-run and mark its acceptance 147 // accordingly. 148 if (!InstallUtil::GetInstallReturnCode(status)) { 149 const bool system_level = installer_state->system_install(); 150 const ProductState* binaries = 151 machine_state.GetProductState(system_level, 152 BrowserDistribution::CHROME_BINARIES); 153 DCHECK(binaries); 154 DWORD eula_accepted; 155 156 if (binaries != NULL && 157 binaries->GetEulaAccepted(&eula_accepted) && 158 eula_accepted == 0 && 159 !GoogleUpdateSettings::SetEULAConsent( 160 machine_state, 161 BrowserDistribution::GetSpecificDistribution( 162 BrowserDistribution::CHROME_BINARIES), 163 true)) { 164 LOG(ERROR) << "Failed to set EULA consent for multi-install binaries."; 165 } 166 } 167 168 return status; 169 } 170 171 } // namespace installer 172