google_chrome_distribution.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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// This file defines specific implementation of BrowserDistribution class for 6// Google Chrome. 7 8#include "chrome/installer/util/google_chrome_distribution.h" 9 10#include <windows.h> 11#include <msi.h> 12 13#include "base/files/file_path.h" 14#include "base/path_service.h" 15#include "base/strings/string_util.h" 16#include "base/strings/stringprintf.h" 17#include "base/strings/utf_string_conversions.h" 18#include "base/win/registry.h" 19#include "base/win/windows_version.h" 20#include "chrome/common/net/test_server_locations.h" 21#include "chrome/installer/util/channel_info.h" 22#include "chrome/installer/util/google_update_constants.h" 23#include "chrome/installer/util/google_update_settings.h" 24#include "chrome/installer/util/helper.h" 25#include "chrome/installer/util/install_util.h" 26#include "chrome/installer/util/l10n_string_util.h" 27#include "chrome/installer/util/uninstall_metrics.h" 28#include "chrome/installer/util/util_constants.h" 29#include "chrome/installer/util/wmi.h" 30#include "content/public/common/result_codes.h" 31 32#include "installer_util_strings.h" // NOLINT 33 34namespace { 35 36const wchar_t kChromeGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}"; 37const wchar_t kBrowserAppId[] = L"Chrome"; 38const wchar_t kBrowserProgIdPrefix[] = L"ChromeHTML"; 39const wchar_t kBrowserProgIdDesc[] = L"Chrome HTML Document"; 40const wchar_t kCommandExecuteImplUuid[] = 41 L"{5C65F4B0-3651-4514-B207-D10CB699B14B}"; 42 43// The Google Chrome App Launcher icon is index 5; see chrome_exe.rc. 44const int kAppLauncherIconIndex = 5; 45 46// Substitute the locale parameter in uninstall URL with whatever 47// Google Update tells us is the locale. In case we fail to find 48// the locale, we use US English. 49base::string16 LocalizeUrl(const wchar_t* url) { 50 base::string16 language; 51 if (!GoogleUpdateSettings::GetLanguage(&language)) 52 language = L"en-US"; // Default to US English. 53 return ReplaceStringPlaceholders(url, language.c_str(), NULL); 54} 55 56base::string16 GetUninstallSurveyUrl() { 57 const wchar_t kSurveyUrl[] = L"http://www.google.com/support/chrome/bin/" 58 L"request.py?hl=$1&contact_type=uninstall"; 59 return LocalizeUrl(kSurveyUrl); 60} 61 62} // namespace 63 64GoogleChromeDistribution::GoogleChromeDistribution() 65 : BrowserDistribution(CHROME_BROWSER), 66 product_guid_(kChromeGuid) { 67} 68 69void GoogleChromeDistribution::DoPostUninstallOperations( 70 const Version& version, 71 const base::FilePath& local_data_path, 72 const base::string16& distribution_data) { 73 // Send the Chrome version and OS version as params to the form. 74 // It would be nice to send the locale, too, but I don't see an 75 // easy way to get that in the existing code. It's something we 76 // can add later, if needed. 77 // We depend on installed_version.GetString() not having spaces or other 78 // characters that need escaping: 0.2.13.4. Should that change, we will 79 // need to escape the string before using it in a URL. 80 const base::string16 kVersionParam = L"crversion"; 81 const base::string16 kOSParam = L"os"; 82 base::win::OSInfo::VersionNumber version_number = 83 base::win::OSInfo::GetInstance()->version_number(); 84 base::string16 os_version = base::StringPrintf(L"%d.%d.%d", 85 version_number.major, version_number.minor, version_number.build); 86 87 base::FilePath iexplore; 88 if (!PathService::Get(base::DIR_PROGRAM_FILES, &iexplore)) 89 return; 90 91 iexplore = iexplore.AppendASCII("Internet Explorer"); 92 iexplore = iexplore.AppendASCII("iexplore.exe"); 93 94 base::string16 command = iexplore.value() + L" " + GetUninstallSurveyUrl() + 95 L"&" + kVersionParam + L"=" + base::UTF8ToWide(version.GetString()) + 96 L"&" + kOSParam + L"=" + os_version; 97 98 base::string16 uninstall_metrics; 99 if (installer::ExtractUninstallMetricsFromFile(local_data_path, 100 &uninstall_metrics)) { 101 // The user has opted into anonymous usage data collection, so append 102 // metrics and distribution data. 103 command += uninstall_metrics; 104 if (!distribution_data.empty()) { 105 command += L"&"; 106 command += distribution_data; 107 } 108 } 109 110 int pid = 0; 111 // The reason we use WMI to launch the process is because the uninstall 112 // process runs inside a Job object controlled by the shell. As long as there 113 // are processes running, the shell will not close the uninstall applet. WMI 114 // allows us to escape from the Job object so the applet will close. 115 installer::WMIProcess::Launch(command, &pid); 116} 117 118base::string16 GoogleChromeDistribution::GetActiveSetupGuid() { 119 return product_guid(); 120} 121 122base::string16 GoogleChromeDistribution::GetAppGuid() { 123 return product_guid(); 124} 125 126base::string16 GoogleChromeDistribution::GetBaseAppName() { 127 // I'd really like to return L ## PRODUCT_FULLNAME_STRING; but that's no good 128 // since it'd be "Chromium" in a non-Chrome build, which isn't at all what I 129 // want. Sigh. 130 return L"Google Chrome"; 131} 132 133base::string16 GoogleChromeDistribution::GetShortcutName( 134 ShortcutType shortcut_type) { 135 int string_id = IDS_PRODUCT_NAME_BASE; 136 switch (shortcut_type) { 137 case SHORTCUT_CHROME_ALTERNATE: 138 string_id = IDS_OEM_MAIN_SHORTCUT_NAME_BASE; 139 break; 140 case SHORTCUT_APP_LAUNCHER: 141 string_id = IDS_APP_LIST_SHORTCUT_NAME_BASE; 142 break; 143 default: 144 DCHECK_EQ(shortcut_type, SHORTCUT_CHROME); 145 break; 146 } 147 return installer::GetLocalizedString(string_id); 148} 149 150int GoogleChromeDistribution::GetIconIndex(ShortcutType shortcut_type) { 151 if (shortcut_type == SHORTCUT_APP_LAUNCHER) 152 return kAppLauncherIconIndex; 153 DCHECK(shortcut_type == SHORTCUT_CHROME || 154 shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type; 155 return 0; 156} 157 158base::string16 GoogleChromeDistribution::GetBaseAppId() { 159 return kBrowserAppId; 160} 161 162base::string16 GoogleChromeDistribution::GetBrowserProgIdPrefix() { 163 return kBrowserProgIdPrefix; 164} 165 166base::string16 GoogleChromeDistribution::GetBrowserProgIdDesc() { 167 return kBrowserProgIdDesc; 168} 169 170base::string16 GoogleChromeDistribution::GetInstallSubDir() { 171 base::string16 sub_dir(installer::kGoogleChromeInstallSubDir1); 172 sub_dir.append(L"\\"); 173 sub_dir.append(installer::kGoogleChromeInstallSubDir2); 174 return sub_dir; 175} 176 177base::string16 GoogleChromeDistribution::GetPublisherName() { 178 const base::string16& publisher_name = 179 installer::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE); 180 return publisher_name; 181} 182 183base::string16 GoogleChromeDistribution::GetAppDescription() { 184 const base::string16& app_description = 185 installer::GetLocalizedString(IDS_SHORTCUT_TOOLTIP_BASE); 186 return app_description; 187} 188 189std::string GoogleChromeDistribution::GetSafeBrowsingName() { 190 return "googlechrome"; 191} 192 193base::string16 GoogleChromeDistribution::GetStateKey() { 194 base::string16 key(google_update::kRegPathClientState); 195 key.append(L"\\"); 196 key.append(product_guid()); 197 return key; 198} 199 200base::string16 GoogleChromeDistribution::GetStateMediumKey() { 201 base::string16 key(google_update::kRegPathClientStateMedium); 202 key.append(L"\\"); 203 key.append(product_guid()); 204 return key; 205} 206 207std::string GoogleChromeDistribution::GetNetworkStatsServer() const { 208 return chrome_common_net::kEchoTestServerLocation; 209} 210 211std::string GoogleChromeDistribution::GetHttpPipeliningTestServer() const { 212 return chrome_common_net::kPipelineTestServerBaseUrl; 213} 214 215base::string16 GoogleChromeDistribution::GetDistributionData(HKEY root_key) { 216 base::string16 sub_key(google_update::kRegPathClientState); 217 sub_key.append(L"\\"); 218 sub_key.append(product_guid()); 219 220 base::win::RegKey client_state_key(root_key, sub_key.c_str(), KEY_READ); 221 base::string16 result; 222 base::string16 brand_value; 223 if (client_state_key.ReadValue(google_update::kRegRLZBrandField, 224 &brand_value) == ERROR_SUCCESS) { 225 result = google_update::kRegRLZBrandField; 226 result.append(L"="); 227 result.append(brand_value); 228 result.append(L"&"); 229 } 230 231 base::string16 client_value; 232 if (client_state_key.ReadValue(google_update::kRegClientField, 233 &client_value) == ERROR_SUCCESS) { 234 result.append(google_update::kRegClientField); 235 result.append(L"="); 236 result.append(client_value); 237 result.append(L"&"); 238 } 239 240 base::string16 ap_value; 241 // If we fail to read the ap key, send up "&ap=" anyway to indicate 242 // that this was probably a stable channel release. 243 client_state_key.ReadValue(google_update::kRegApField, &ap_value); 244 result.append(google_update::kRegApField); 245 result.append(L"="); 246 result.append(ap_value); 247 248 return result; 249} 250 251base::string16 GoogleChromeDistribution::GetUninstallLinkName() { 252 const base::string16& link_name = 253 installer::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE); 254 return link_name; 255} 256 257base::string16 GoogleChromeDistribution::GetUninstallRegPath() { 258 return L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" 259 L"Google Chrome"; 260} 261 262base::string16 GoogleChromeDistribution::GetVersionKey() { 263 base::string16 key(google_update::kRegPathClients); 264 key.append(L"\\"); 265 key.append(product_guid()); 266 return key; 267} 268 269base::string16 GoogleChromeDistribution::GetIconFilename() { 270 return installer::kChromeExe; 271} 272 273bool GoogleChromeDistribution::GetCommandExecuteImplClsid( 274 base::string16* handler_class_uuid) { 275 if (handler_class_uuid) 276 *handler_class_uuid = kCommandExecuteImplUuid; 277 return true; 278} 279 280bool GoogleChromeDistribution::AppHostIsSupported() { 281 return true; 282} 283 284// This method checks if we need to change "ap" key in Google Update to try 285// full installer as fall back method in case incremental installer fails. 286// - If incremental installer fails we append a magic string ("-full"), if 287// it is not present already, so that Google Update server next time will send 288// full installer to update Chrome on the local machine 289// - If we are currently running full installer, we remove this magic 290// string (if it is present) regardless of whether installer failed or not. 291// There is no fall-back for full installer :) 292void GoogleChromeDistribution::UpdateInstallStatus(bool system_install, 293 installer::ArchiveType archive_type, 294 installer::InstallStatus install_status) { 295 GoogleUpdateSettings::UpdateInstallStatus(system_install, 296 archive_type, InstallUtil::GetInstallReturnCode(install_status), 297 product_guid()); 298} 299 300bool GoogleChromeDistribution::ShouldSetExperimentLabels() { 301 return true; 302} 303 304bool GoogleChromeDistribution::HasUserExperiments() { 305 return true; 306} 307