1 // Copyright (c) 2011 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_ready_mode.h" 6 7 #include "base/command_line.h" 8 #include "base/files/file_path.h" 9 #include "base/logging.h" 10 #include "base/memory/ref_counted.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/time/time.h" 14 #include "base/win/registry.h" 15 #include "chrome/installer/setup/install.h" 16 #include "chrome/installer/setup/install_worker.h" 17 #include "chrome/installer/util/browser_distribution.h" 18 #include "chrome/installer/util/google_update_constants.h" 19 #include "chrome/installer/util/helper.h" 20 #include "chrome/installer/util/install_util.h" 21 #include "chrome/installer/util/installation_state.h" 22 #include "chrome/installer/util/installer_state.h" 23 #include "chrome/installer/util/master_preferences.h" 24 #include "chrome/installer/util/master_preferences_constants.h" 25 #include "chrome/installer/util/product.h" 26 #include "chrome/installer/util/util_constants.h" 27 #include "chrome/installer/util/work_item.h" 28 #include "chrome/installer/util/work_item_list.h" 29 30 namespace installer { 31 32 // If Chrome is not multi-installed at the appropriate level, error. 33 // If Chrome Frame is already multi-installed at the appropriate level, noop. 34 // If Chrome Frame is single-installed at the appropriate level, error. 35 // Add uninstall for Chrome Frame. 36 // Update uninstall for Chrome. 37 // Update ChannelInfo for all multi-installed products. 38 // Remove ready-mode. 39 InstallStatus ChromeFrameReadyModeOptIn( 40 const InstallationState& machine_state, 41 const InstallerState& installer_state) { 42 VLOG(1) << "Opting into Chrome Frame"; 43 InstallStatus status = INSTALL_REPAIRED; 44 45 // Make sure Chrome and Chrome Frame are both multi-installed. 46 const ProductState* chrome_state = 47 machine_state.GetProductState(installer_state.system_install(), 48 BrowserDistribution::CHROME_BROWSER); 49 const ProductState* cf_state = 50 machine_state.GetProductState(installer_state.system_install(), 51 BrowserDistribution::CHROME_FRAME); 52 if (chrome_state == NULL) { 53 LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome."; 54 return CHROME_NOT_INSTALLED; 55 } 56 if (!chrome_state->is_multi_install()) { 57 LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome."; 58 return NON_MULTI_INSTALLATION_EXISTS; 59 } 60 if (cf_state == NULL) { 61 LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame."; 62 return CHROME_NOT_INSTALLED; 63 } 64 if (!cf_state->is_multi_install()) { 65 LOG(ERROR) << "Chrome Frame opt-in requires multi-install of Chrome Frame."; 66 return NON_MULTI_INSTALLATION_EXISTS; 67 } 68 69 // Create a new InstallerState to be used for this operation. 70 InstallerState opt_in_state(installer_state.level()); 71 72 // Add the two products we're going to operate on. 73 const Product* chrome = 74 opt_in_state.AddProductFromState(BrowserDistribution::CHROME_BROWSER, 75 *chrome_state); 76 Product* cf = 77 opt_in_state.AddProductFromState(BrowserDistribution::CHROME_FRAME, 78 *cf_state); 79 // DCHECKs will fire in this case if it ever happens (it won't). 80 if (chrome == NULL || cf == NULL) 81 return READY_MODE_OPT_IN_FAILED; 82 83 // Turn off ready-mode on Chrome Frame, thereby making it fully installed. 84 if (!cf->SetOption(kOptionReadyMode, false)) { 85 LOG(WARNING) 86 << "Chrome Frame is already fully installed; opting-in nonetheless."; 87 } 88 89 // Update Chrome's uninstallation commands to only uninstall Chrome, and add 90 // an entry to the Add/Remove Programs dialog for GCF. 91 DCHECK(cf->ShouldCreateUninstallEntry() || opt_in_state.is_msi()); 92 93 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); 94 95 // This creates the uninstallation entry for GCF. 96 AddUninstallShortcutWorkItems(opt_in_state, cf_state->GetSetupPath(), 97 cf_state->version(), *cf, item_list.get()); 98 // This updates the Chrome uninstallation entries. 99 AddUninstallShortcutWorkItems(opt_in_state, chrome_state->GetSetupPath(), 100 chrome_state->version(), *chrome, item_list.get()); 101 102 // Add a work item to delete the ChromeFrameReadyMode registry value. 103 HKEY root = opt_in_state.root_key(); 104 item_list->AddDeleteRegValueWorkItem(root, 105 opt_in_state.multi_package_binaries_distribution()->GetStateKey(), 106 kChromeFrameReadyModeField); 107 108 // Update the Google Update channel ("ap") value. 109 AddGoogleUpdateWorkItems(machine_state, opt_in_state, item_list.get()); 110 111 // Delete the command elevation registry keys 112 std::wstring version_key(cf->distribution()->GetVersionKey()); 113 item_list->AddDeleteRegValueWorkItem( 114 root, version_key, google_update::kRegCFTempOptOutCmdField); 115 item_list->AddDeleteRegValueWorkItem( 116 root, version_key, google_update::kRegCFEndTempOptOutCmdField); 117 item_list->AddDeleteRegValueWorkItem(root, version_key, 118 google_update::kRegCFOptOutCmdField); 119 item_list->AddDeleteRegValueWorkItem(root, version_key, 120 google_update::kRegCFOptInCmdField); 121 122 if (!item_list->Do()) { 123 LOG(ERROR) << "Failed to opt into GCF"; 124 item_list->Rollback(); 125 status = READY_MODE_OPT_IN_FAILED; 126 } 127 128 return status; 129 } 130 131 const wchar_t kPostPlatformUAKey[] = 132 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\" 133 L"User Agent\\Post Platform"; 134 const wchar_t kChromeFramePrefix[] = L"chromeframe/"; 135 136 InstallStatus ChromeFrameReadyModeTempOptOut( 137 const InstallationState& machine_state, 138 const InstallerState& installer_state) { 139 VLOG(1) << "Temporarily opting out of Chrome Frame"; 140 InstallStatus status = INSTALL_REPAIRED; 141 142 // Make sure Chrome Frame is multi-installed. 143 const ProductState* cf_state = 144 machine_state.GetProductState(installer_state.system_install(), 145 BrowserDistribution::CHROME_FRAME); 146 if (cf_state == NULL) { 147 LOG(ERROR) 148 << "Chrome Frame temp opt-out requires multi-install of Chrome Frame."; 149 return CHROME_NOT_INSTALLED; 150 } 151 if (!cf_state->is_multi_install()) { 152 LOG(ERROR) 153 << "Chrome Frame temp opt-out requires multi-install of Chrome Frame."; 154 return NON_MULTI_INSTALLATION_EXISTS; 155 } 156 157 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); 158 159 HKEY root = installer_state.root_key(); 160 161 // Add a work item to delete the ChromeFrame user agent registry value. 162 base::win::RegistryValueIterator values(root, kPostPlatformUAKey); 163 while (values.Valid()) { 164 const wchar_t* name = values.Name(); 165 if (StartsWith(name, kChromeFramePrefix, true)) { 166 item_list->AddDeleteRegValueWorkItem(root, kPostPlatformUAKey, name); 167 } 168 ++values; 169 } 170 171 // Add a work item to update the Ready Mode state flag 172 int64 timestamp = base::Time::Now().ToInternalValue(); 173 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 174 BrowserDistribution::CHROME_BINARIES); 175 item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(), 176 kChromeFrameReadyModeField, timestamp, 177 true); 178 179 if (!item_list->Do()) { 180 LOG(ERROR) << "Failed to temporarily opt out of GCF"; 181 item_list->Rollback(); 182 status = READY_MODE_TEMP_OPT_OUT_FAILED; 183 } 184 185 return status; 186 } 187 188 InstallStatus ChromeFrameReadyModeEndTempOptOut( 189 const InstallationState& machine_state, 190 const InstallerState& installer_state) { 191 VLOG(1) << "Ending temporary opt-out of Chrome Frame"; 192 InstallStatus status = INSTALL_REPAIRED; 193 194 // Make sure Chrome Frame is multi-installed. 195 const ProductState* cf_state = 196 machine_state.GetProductState(installer_state.system_install(), 197 BrowserDistribution::CHROME_FRAME); 198 if (cf_state == NULL) { 199 LOG(ERROR) 200 << "Chrome Frame temp opt-out requires multi-install of Chrome Frame."; 201 return CHROME_NOT_INSTALLED; 202 } 203 if (!cf_state->is_multi_install()) { 204 LOG(ERROR) 205 << "Chrome Frame temp opt-out requires multi-install of Chrome Frame."; 206 return NON_MULTI_INSTALLATION_EXISTS; 207 } 208 209 // Replace the ChromeFrame user agent string in the registry, modify the 210 // ReadyMode state flag. 211 const Version& installed_version = cf_state->version(); 212 213 scoped_ptr<WorkItemList> item_list(WorkItem::CreateWorkItemList()); 214 215 HKEY root = installer_state.root_key(); 216 217 std::wstring chrome_frame_ua_value_name(kChromeFramePrefix); 218 chrome_frame_ua_value_name += ASCIIToWide(installed_version.GetString()); 219 220 // Store the Chrome Frame user agent string 221 item_list->AddSetRegValueWorkItem(root, kPostPlatformUAKey, 222 chrome_frame_ua_value_name, L"", true); 223 // Add a work item to update the Ready Mode state flag 224 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 225 BrowserDistribution::CHROME_BINARIES); 226 item_list->AddSetRegValueWorkItem(root, dist->GetStateKey(), 227 kChromeFrameReadyModeField, 228 static_cast<int64>(1), true); 229 230 if (!item_list->Do()) { 231 LOG(ERROR) << "Failed to end temporary opt out of GCF"; 232 item_list->Rollback(); 233 status = READY_MODE_END_TEMP_OPT_OUT_FAILED; 234 } 235 236 return status; 237 } 238 239 } // namespace installer 240