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/browser/google/google_update_win.h"
6
7#include <atlbase.h>
8#include <atlcom.h>
9
10#include "base/bind.h"
11#include "base/files/file_path.h"
12#include "base/message_loop/message_loop.h"
13#include "base/metrics/histogram.h"
14#include "base/metrics/sparse_histogram.h"
15#include "base/path_service.h"
16#include "base/strings/string_util.h"
17#include "base/strings/stringprintf.h"
18#include "base/threading/thread.h"
19#include "base/win/scoped_comptr.h"
20#include "base/win/windows_version.h"
21#include "chrome/grit/generated_resources.h"
22#include "chrome/installer/util/browser_distribution.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 "content/public/browser/browser_thread.h"
27#include "google_update/google_update_idl.h"
28#include "ui/base/l10n/l10n_util.h"
29#include "ui/base/win/atl_module.h"
30#include "ui/views/widget/widget.h"
31
32using content::BrowserThread;
33
34namespace {
35
36// Check if the currently running instance can be updated by Google Update.
37// Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
38// Chrome distribution installed in a standard location.
39GoogleUpdateErrorCode CanUpdateCurrentChrome(
40    const base::FilePath& chrome_exe_path) {
41#if !defined(GOOGLE_CHROME_BUILD)
42  return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
43#else
44  // TODO(tommi): Check if using the default distribution is always the right
45  // thing to do.
46  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
47  base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
48  base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
49  if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
50                                        user_exe_path.value()) &&
51      !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
52                                        machine_exe_path.value())) {
53    LOG(ERROR) << L"Google Update cannot update Chrome installed in a "
54               << L"non-standard location: " << chrome_exe_path.value().c_str()
55               << L". The standard location is: "
56                   << user_exe_path.value().c_str()
57               << L" or " << machine_exe_path.value().c_str() << L".";
58    return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
59  }
60
61  base::string16 app_guid = installer::GetAppGuidForUpdates(
62      !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
63  DCHECK(!app_guid.empty());
64
65  GoogleUpdateSettings::UpdatePolicy update_policy =
66      GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
67
68  if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
69    return GOOGLE_UPDATE_DISABLED_BY_POLICY;
70
71  if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
72    return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
73
74  return GOOGLE_UPDATE_NO_ERROR;
75#endif
76}
77
78// Creates an instance of a COM Local Server class using either plain vanilla
79// CoCreateInstance, or using the Elevation moniker if running on Vista.
80// hwnd must refer to a foregound window in order to get the UAC prompt
81// showing up in the foreground if running on Vista. It can also be NULL if
82// background UAC prompts are desired.
83HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
84                                HWND hwnd, void** interface_ptr) {
85  if (!interface_ptr)
86    return E_POINTER;
87
88  // For Vista, need to instantiate the COM server via the elevation
89  // moniker. This ensures that the UAC dialog shows up.
90  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
91    wchar_t class_id_as_string[MAX_PATH] = {0};
92    StringFromGUID2(class_id, class_id_as_string,
93                    arraysize(class_id_as_string));
94
95    base::string16 elevation_moniker_name =
96        base::StringPrintf(L"Elevation:Administrator!new:%ls",
97                           class_id_as_string);
98
99    BIND_OPTS3 bind_opts;
100    memset(&bind_opts, 0, sizeof(bind_opts));
101    bind_opts.cbStruct = sizeof(bind_opts);
102    bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
103    bind_opts.hwnd = hwnd;
104
105    return CoGetObject(elevation_moniker_name.c_str(), &bind_opts,
106                       interface_id, reinterpret_cast<void**>(interface_ptr));
107  }
108
109  return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER,
110                          interface_id,
111                          reinterpret_cast<void**>(interface_ptr));
112}
113
114
115}  // namespace
116
117// The GoogleUpdateJobObserver COM class is responsible for receiving status
118// reports from google Update. It keeps track of the progress as GoogleUpdate
119// notifies this observer and ends the message loop that is spinning in once
120// GoogleUpdate reports that it is done.
121class GoogleUpdateJobObserver
122  : public CComObjectRootEx<CComSingleThreadModel>,
123    public IJobObserver {
124 public:
125  BEGIN_COM_MAP(GoogleUpdateJobObserver)
126    COM_INTERFACE_ENTRY(IJobObserver)
127  END_COM_MAP()
128
129  GoogleUpdateJobObserver()
130    : result_(UPGRADE_ERROR) {
131  }
132  virtual ~GoogleUpdateJobObserver() {}
133
134  // Notifications from Google Update:
135  STDMETHOD(OnShow)() {
136    return S_OK;
137  }
138  STDMETHOD(OnCheckingForUpdate)() {
139    result_ = UPGRADE_CHECK_STARTED;
140    return S_OK;
141  }
142  STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
143    result_ = UPGRADE_IS_AVAILABLE;
144    new_version_ = version_string;
145    return S_OK;
146  }
147  STDMETHOD(OnWaitingToDownload)() {
148    return S_OK;
149  }
150  STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
151    return S_OK;
152  }
153  STDMETHOD(OnWaitingToInstall)() {
154    return S_OK;
155  }
156  STDMETHOD(OnInstalling)() {
157    result_ = UPGRADE_STARTED;
158    return S_OK;
159  }
160  STDMETHOD(OnPause)() {
161    return S_OK;
162  }
163  STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
164    switch (code) {
165      case COMPLETION_CODE_SUCCESS_CLOSE_UI:
166      case COMPLETION_CODE_SUCCESS: {
167        if (result_ == UPGRADE_STARTED)
168          result_ = UPGRADE_SUCCESSFUL;
169        else if (result_ == UPGRADE_CHECK_STARTED)
170          result_ = UPGRADE_ALREADY_UP_TO_DATE;
171        break;
172      }
173      case COMPLETION_CODE_ERROR:
174        error_message_ = text;
175      default: {
176        NOTREACHED();
177        result_ = UPGRADE_ERROR;
178        break;
179      }
180    }
181
182    event_sink_ = NULL;
183
184    // No longer need to spin the message loop that started spinning in
185    // InitiateGoogleUpdateCheck.
186    base::MessageLoop::current()->Quit();
187    return S_OK;
188  }
189  STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink) {
190    event_sink_ = event_sink;
191    return S_OK;
192  }
193
194  // Returns the results of the update operation.
195  STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) {
196    // Intermediary steps should never be reported to the client.
197    DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED);
198
199    *result = result_;
200    return S_OK;
201  }
202
203  // Returns which version Google Update found on the server (if a more
204  // recent version was found). Otherwise, this will be blank.
205  STDMETHOD(GetVersionInfo)(base::string16* version_string) {
206    *version_string = new_version_;
207    return S_OK;
208  }
209
210  // Returns the Google Update supplied error string that describes the error
211  // that occurred during the update check/upgrade.
212  STDMETHOD(GetErrorMessage)(base::string16* error_message) {
213    *error_message = error_message_;
214    return S_OK;
215  }
216
217 private:
218  // The status/result of the Google Update operation.
219  GoogleUpdateUpgradeResult result_;
220
221  // The version string Google Update found.
222  base::string16 new_version_;
223
224  // An error message, if any.
225  base::string16 error_message_;
226
227  // Allows us control the upgrade process to a small degree. After OnComplete
228  // has been called, this object can not be used.
229  base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
230};
231
232////////////////////////////////////////////////////////////////////////////////
233// GoogleUpdate, public:
234
235GoogleUpdate::GoogleUpdate()
236    : listener_(NULL) {
237}
238
239GoogleUpdate::~GoogleUpdate() {
240}
241
242void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) {
243  // Need to shunt this request over to InitiateGoogleUpdateCheck and have
244  // it run in the file thread.
245  BrowserThread::PostTask(
246      BrowserThread::FILE, FROM_HERE,
247      base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this,
248                 install_if_newer, window, base::MessageLoop::current()));
249}
250
251////////////////////////////////////////////////////////////////////////////////
252// GoogleUpdate, private:
253
254void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer,
255                                             HWND window,
256                                             base::MessageLoop* main_loop) {
257  base::FilePath chrome_exe;
258  if (!PathService::Get(base::DIR_EXE, &chrome_exe))
259    NOTREACHED();
260
261  GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe);
262  if (error_code != GOOGLE_UPDATE_NO_ERROR) {
263    main_loop->PostTask(
264        FROM_HERE,
265        base::Bind(&GoogleUpdate::ReportResults, this,
266                   UPGRADE_ERROR, error_code, base::string16()));
267    return;
268  }
269
270  // Make sure ATL is initialized in this module.
271  ui::win::CreateATLModuleIfNeeded();
272
273  CComObject<GoogleUpdateJobObserver>* job_observer;
274  HRESULT hr =
275      CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer);
276  if (hr != S_OK) {
277    // Most of the error messages come straight from Google Update. This one is
278    // deemed worthy enough to also warrant its own error.
279    GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED;
280    base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
281    ReportFailure(
282        hr, error,
283        l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
284                                   error_code),
285        main_loop);
286    return;
287  }
288
289  base::win::ScopedComPtr<IJobObserver> job_holder(job_observer);
290
291  base::win::ScopedComPtr<IGoogleUpdate> on_demand;
292
293  bool system_level = false;
294
295  if (InstallUtil::IsPerUserInstall(chrome_exe.value().c_str())) {
296    hr = on_demand.CreateInstance(CLSID_OnDemandUserAppsClass);
297  } else {
298    // The Update operation needs Admin privileges for writing
299    // to %ProgramFiles%. On Vista, need to elevate before instantiating
300    // the updater instance.
301    if (!install_if_newer) {
302      hr = on_demand.CreateInstance(CLSID_OnDemandMachineAppsClass);
303    } else {
304      hr = CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
305          IID_IGoogleUpdate, window,
306          reinterpret_cast<void**>(on_demand.Receive()));
307    }
308    system_level = true;
309  }
310
311  if (hr != S_OK) {
312    GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND;
313    base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
314    if (system_level)
315      error_code += L" -- system level";
316    ReportFailure(hr, error,
317                  l10n_util::GetStringFUTF16(
318                      IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
319                      error_code),
320                  main_loop);
321    return;
322  }
323
324  base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
325  DCHECK(!app_guid.empty());
326
327  if (!install_if_newer)
328    hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer);
329  else
330    hr = on_demand->Update(app_guid.c_str(), job_observer);
331
332  if (hr != S_OK) {
333    GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR;
334    base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
335    ReportFailure(hr, error,
336                  l10n_util::GetStringFUTF16(
337                      IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
338                      error_code),
339                  main_loop);
340    return;
341  }
342
343  // Need to spin the message loop while Google Update is running so that it
344  // can report back to us through GoogleUpdateJobObserver. This message loop
345  // will terminate once Google Update sends us the completion status
346  // (success/error). See OnComplete().
347  base::MessageLoop::current()->Run();
348
349  GoogleUpdateUpgradeResult results;
350  hr = job_observer->GetResult(&results);
351
352  if (hr != S_OK) {
353    GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED;
354    base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
355    ReportFailure(hr, error,
356                  l10n_util::GetStringFUTF16(
357                      IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
358                      error_code),
359                  main_loop);
360    return;
361  }
362
363  if (results == UPGRADE_ERROR) {
364    base::string16 error_message;
365    job_observer->GetErrorMessage(&error_message);
366    ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop);
367    return;
368  }
369
370  hr = job_observer->GetVersionInfo(&version_available_);
371  if (hr != S_OK) {
372    GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED;
373    base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr);
374    ReportFailure(hr, error,
375                  l10n_util::GetStringFUTF16(
376                      IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED,
377                      error_code),
378                  main_loop);
379    return;
380  }
381
382  main_loop->PostTask(
383      FROM_HERE,
384      base::Bind(&GoogleUpdate::ReportResults, this,
385                 results, GOOGLE_UPDATE_NO_ERROR, base::string16()));
386  job_holder = NULL;
387  on_demand = NULL;
388}
389
390void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results,
391                                 GoogleUpdateErrorCode error_code,
392                                 const base::string16& error_message) {
393  // If there is an error, then error code must not be blank, and vice versa.
394  DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR :
395                                    error_code == GOOGLE_UPDATE_NO_ERROR);
396  UMA_HISTOGRAM_ENUMERATION(
397      "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS);
398  if (results == UPGRADE_ERROR) {
399    UMA_HISTOGRAM_ENUMERATION(
400        "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES);
401  }
402  if (listener_) {
403    listener_->OnReportResults(
404        results, error_code, error_message, version_available_);
405  }
406}
407
408bool GoogleUpdate::ReportFailure(HRESULT hr,
409                                 GoogleUpdateErrorCode error_code,
410                                 const base::string16& error_message,
411                                 base::MessageLoop* main_loop) {
412  DLOG(ERROR) << "Communication with Google Update failed: " << hr
413              << " error: " << error_code
414              << ", message: " << error_message.c_str();
415  UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hr);
416  main_loop->PostTask(
417      FROM_HERE,
418      base::Bind(&GoogleUpdate::ReportResults, this,
419                 UPGRADE_ERROR, error_code, error_message));
420  return false;
421}
422