Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(205)

Side by Side Diff: chrome/browser/google/google_update.cc

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

Powered by Google App Engine
This is Rietveld 408576698