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