• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 using content::BrowserThread;
33 
34 namespace {
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.
CanUpdateCurrentChrome(const base::FilePath & chrome_exe_path)39 GoogleUpdateErrorCode 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.
CoCreateInstanceAsAdmin(REFCLSID class_id,REFIID interface_id,HWND hwnd,void ** interface_ptr)83 HRESULT 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.
121 class GoogleUpdateJobObserver
122   : public CComObjectRootEx<CComSingleThreadModel>,
123     public IJobObserver {
124  public:
125   BEGIN_COM_MAP(GoogleUpdateJobObserver)
COM_INTERFACE_ENTRY(IJobObserver)126     COM_INTERFACE_ENTRY(IJobObserver)
127   END_COM_MAP()
128 
129   GoogleUpdateJobObserver()
130     : result_(UPGRADE_ERROR) {
131   }
~GoogleUpdateJobObserver()132   virtual ~GoogleUpdateJobObserver() {}
133 
134   // Notifications from Google Update:
STDMETHOD(OnShow)135   STDMETHOD(OnShow)() {
136     return S_OK;
137   }
STDMETHOD(OnCheckingForUpdate)138   STDMETHOD(OnCheckingForUpdate)() {
139     result_ = UPGRADE_CHECK_STARTED;
140     return S_OK;
141   }
STDMETHOD(OnUpdateAvailable)142   STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string) {
143     result_ = UPGRADE_IS_AVAILABLE;
144     new_version_ = version_string;
145     return S_OK;
146   }
STDMETHOD(OnWaitingToDownload)147   STDMETHOD(OnWaitingToDownload)() {
148     return S_OK;
149   }
STDMETHOD(OnDownloading)150   STDMETHOD(OnDownloading)(int time_remaining_ms, int pos) {
151     return S_OK;
152   }
STDMETHOD(OnWaitingToInstall)153   STDMETHOD(OnWaitingToInstall)() {
154     return S_OK;
155   }
STDMETHOD(OnInstalling)156   STDMETHOD(OnInstalling)() {
157     result_ = UPGRADE_STARTED;
158     return S_OK;
159   }
STDMETHOD(OnPause)160   STDMETHOD(OnPause)() {
161     return S_OK;
162   }
STDMETHOD(OnComplete)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   }
STDMETHOD(SetEventSink)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.
STDMETHOD(GetResult)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.
STDMETHOD(GetVersionInfo)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.
STDMETHOD(GetErrorMessage)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 
GoogleUpdate()235 GoogleUpdate::GoogleUpdate()
236     : listener_(NULL) {
237 }
238 
~GoogleUpdate()239 GoogleUpdate::~GoogleUpdate() {
240 }
241 
CheckForUpdate(bool install_if_newer,HWND window)242 void 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 
InitiateGoogleUpdateCheck(bool install_if_newer,HWND window,base::MessageLoop * main_loop)254 void 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 
ReportResults(GoogleUpdateUpgradeResult results,GoogleUpdateErrorCode error_code,const base::string16 & error_message)390 void 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 
ReportFailure(HRESULT hr,GoogleUpdateErrorCode error_code,const base::string16 & error_message,base::MessageLoop * main_loop)408 bool 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