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