google_chrome_distribution.cc revision f2477e01787aa58f445919b809d89e252beef54f
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. 49string16 LocalizeUrl(const wchar_t* url) { 50 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 56string16 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 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 string16 kVersionParam = L"crversion"; 81 const string16 kOSParam = L"os"; 82 base::win::OSInfo::VersionNumber version_number = 83 base::win::OSInfo::GetInstance()->version_number(); 84 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 string16 command = iexplore.value() + L" " + GetUninstallSurveyUrl() + 95 L"&" + kVersionParam + L"=" + UTF8ToWide(version.GetString()) + L"&" + 96 kOSParam + L"=" + os_version; 97 98 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 118string16 GoogleChromeDistribution::GetActiveSetupGuid() { 119 return product_guid(); 120} 121 122string16 GoogleChromeDistribution::GetAppGuid() { 123 return product_guid(); 124} 125 126string16 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 133string16 GoogleChromeDistribution::GetShortcutName(ShortcutType shortcut_type) { 134 int string_id = IDS_PRODUCT_NAME_BASE; 135 switch (shortcut_type) { 136 case SHORTCUT_CHROME_ALTERNATE: 137 string_id = IDS_OEM_MAIN_SHORTCUT_NAME_BASE; 138 break; 139 case SHORTCUT_APP_LAUNCHER: 140 string_id = IDS_APP_LIST_SHORTCUT_NAME_BASE; 141 break; 142 default: 143 DCHECK_EQ(shortcut_type, SHORTCUT_CHROME); 144 break; 145 } 146 return installer::GetLocalizedString(string_id); 147} 148 149int GoogleChromeDistribution::GetIconIndex(ShortcutType shortcut_type) { 150 if (shortcut_type == SHORTCUT_APP_LAUNCHER) 151 return kAppLauncherIconIndex; 152 DCHECK(shortcut_type == SHORTCUT_CHROME || 153 shortcut_type == SHORTCUT_CHROME_ALTERNATE) << shortcut_type; 154 return 0; 155} 156 157string16 GoogleChromeDistribution::GetBaseAppId() { 158 return kBrowserAppId; 159} 160 161string16 GoogleChromeDistribution::GetBrowserProgIdPrefix() { 162 return kBrowserProgIdPrefix; 163} 164 165string16 GoogleChromeDistribution::GetBrowserProgIdDesc() { 166 return kBrowserProgIdDesc; 167} 168 169string16 GoogleChromeDistribution::GetInstallSubDir() { 170 string16 sub_dir(installer::kGoogleChromeInstallSubDir1); 171 sub_dir.append(L"\\"); 172 sub_dir.append(installer::kGoogleChromeInstallSubDir2); 173 return sub_dir; 174} 175 176string16 GoogleChromeDistribution::GetPublisherName() { 177 const string16& publisher_name = 178 installer::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE); 179 return publisher_name; 180} 181 182string16 GoogleChromeDistribution::GetAppDescription() { 183 const string16& app_description = 184 installer::GetLocalizedString(IDS_SHORTCUT_TOOLTIP_BASE); 185 return app_description; 186} 187 188std::string GoogleChromeDistribution::GetSafeBrowsingName() { 189 return "googlechrome"; 190} 191 192string16 GoogleChromeDistribution::GetStateKey() { 193 string16 key(google_update::kRegPathClientState); 194 key.append(L"\\"); 195 key.append(product_guid()); 196 return key; 197} 198 199string16 GoogleChromeDistribution::GetStateMediumKey() { 200 string16 key(google_update::kRegPathClientStateMedium); 201 key.append(L"\\"); 202 key.append(product_guid()); 203 return key; 204} 205 206std::string GoogleChromeDistribution::GetNetworkStatsServer() const { 207 return chrome_common_net::kEchoTestServerLocation; 208} 209 210std::string GoogleChromeDistribution::GetHttpPipeliningTestServer() const { 211 return chrome_common_net::kPipelineTestServerBaseUrl; 212} 213 214string16 GoogleChromeDistribution::GetDistributionData(HKEY root_key) { 215 string16 sub_key(google_update::kRegPathClientState); 216 sub_key.append(L"\\"); 217 sub_key.append(product_guid()); 218 219 base::win::RegKey client_state_key(root_key, sub_key.c_str(), KEY_READ); 220 string16 result; 221 string16 brand_value; 222 if (client_state_key.ReadValue(google_update::kRegRLZBrandField, 223 &brand_value) == ERROR_SUCCESS) { 224 result = google_update::kRegRLZBrandField; 225 result.append(L"="); 226 result.append(brand_value); 227 result.append(L"&"); 228 } 229 230 string16 client_value; 231 if (client_state_key.ReadValue(google_update::kRegClientField, 232 &client_value) == ERROR_SUCCESS) { 233 result.append(google_update::kRegClientField); 234 result.append(L"="); 235 result.append(client_value); 236 result.append(L"&"); 237 } 238 239 string16 ap_value; 240 // If we fail to read the ap key, send up "&ap=" anyway to indicate 241 // that this was probably a stable channel release. 242 client_state_key.ReadValue(google_update::kRegApField, &ap_value); 243 result.append(google_update::kRegApField); 244 result.append(L"="); 245 result.append(ap_value); 246 247 return result; 248} 249 250string16 GoogleChromeDistribution::GetUninstallLinkName() { 251 const string16& link_name = 252 installer::GetLocalizedString(IDS_UNINSTALL_CHROME_BASE); 253 return link_name; 254} 255 256string16 GoogleChromeDistribution::GetUninstallRegPath() { 257 return L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" 258 L"Google Chrome"; 259} 260 261string16 GoogleChromeDistribution::GetVersionKey() { 262 string16 key(google_update::kRegPathClients); 263 key.append(L"\\"); 264 key.append(product_guid()); 265 return key; 266} 267 268string16 GoogleChromeDistribution::GetIconFilename() { 269 return installer::kChromeExe; 270} 271 272bool GoogleChromeDistribution::GetCommandExecuteImplClsid( 273 string16* handler_class_uuid) { 274 if (handler_class_uuid) 275 *handler_class_uuid = kCommandExecuteImplUuid; 276 return true; 277} 278 279bool GoogleChromeDistribution::AppHostIsSupported() { 280 return true; 281} 282 283// This method checks if we need to change "ap" key in Google Update to try 284// full installer as fall back method in case incremental installer fails. 285// - If incremental installer fails we append a magic string ("-full"), if 286// it is not present already, so that Google Update server next time will send 287// full installer to update Chrome on the local machine 288// - If we are currently running full installer, we remove this magic 289// string (if it is present) regardless of whether installer failed or not. 290// There is no fall-back for full installer :) 291void GoogleChromeDistribution::UpdateInstallStatus(bool system_install, 292 installer::ArchiveType archive_type, 293 installer::InstallStatus install_status) { 294 GoogleUpdateSettings::UpdateInstallStatus(system_install, 295 archive_type, InstallUtil::GetInstallReturnCode(install_status), 296 product_guid()); 297} 298 299bool GoogleChromeDistribution::ShouldSetExperimentLabels() { 300 return true; 301} 302 303bool GoogleChromeDistribution::HasUserExperiments() { 304 return true; 305} 306