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

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

Issue 729273002: Modernize on-demand update checks on Windows. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments Created 6 years 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/google/google_update_win.h" 5 #include "chrome/browser/google/google_update_win.h"
6 6
7 #include <atlbase.h> 7 #include <atlbase.h>
8 #include <atlcom.h> 8 #include <atlcom.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h"
11 #include "base/files/file_path.h" 12 #include "base/files/file_path.h"
12 #include "base/message_loop/message_loop.h" 13 #include "base/location.h"
13 #include "base/metrics/histogram.h" 14 #include "base/metrics/histogram.h"
14 #include "base/metrics/sparse_histogram.h" 15 #include "base/metrics/sparse_histogram.h"
15 #include "base/path_service.h" 16 #include "base/path_service.h"
16 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
18 #include "base/threading/thread.h" 19 #include "base/task_runner.h"
19 #include "base/win/scoped_comptr.h" 20 #include "base/thread_task_runner_handle.h"
20 #include "base/win/windows_version.h" 21 #include "base/win/windows_version.h"
21 #include "chrome/grit/generated_resources.h" 22 #include "chrome/grit/generated_resources.h"
22 #include "chrome/installer/util/browser_distribution.h" 23 #include "chrome/installer/util/browser_distribution.h"
23 #include "chrome/installer/util/google_update_settings.h" 24 #include "chrome/installer/util/google_update_settings.h"
24 #include "chrome/installer/util/helper.h" 25 #include "chrome/installer/util/helper.h"
25 #include "chrome/installer/util/install_util.h" 26 #include "chrome/installer/util/install_util.h"
26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
27 #include "google_update/google_update_idl.h"
28 #include "ui/base/l10n/l10n_util.h" 28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/base/win/atl_module.h" 29 #include "ui/base/win/atl_module.h"
30 #include "ui/views/widget/widget.h"
31
32 using content::BrowserThread;
33 30
34 namespace { 31 namespace {
35 32
33 internal::OnDemandAppsClassFactory* g_google_update_factory = nullptr;
34
36 // Check if the currently running instance can be updated by Google Update. 35 // 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 36 // Returns GOOGLE_UPDATE_NO_ERROR only if the instance running is a Google
38 // Chrome distribution installed in a standard location. 37 // Chrome distribution installed in a standard location.
39 GoogleUpdateErrorCode CanUpdateCurrentChrome( 38 GoogleUpdateErrorCode CanUpdateCurrentChrome(
40 const base::FilePath& chrome_exe_path) { 39 const base::FilePath& chrome_exe_path,
40 bool system_level) {
41 #if !defined(GOOGLE_CHROME_BUILD) 41 #if !defined(GOOGLE_CHROME_BUILD)
42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY; 42 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
43 #else 43 #else
44 // TODO(tommi): Check if using the default distribution is always the right 44 DCHECK_NE(InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()),
45 // thing to do. 45 system_level);
46 BrowserDistribution* dist = BrowserDistribution::GetDistribution(); 46 BrowserDistribution* dist = BrowserDistribution::GetDistribution();
47 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist); 47 base::FilePath user_exe_path = installer::GetChromeInstallPath(false, dist);
48 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist); 48 base::FilePath machine_exe_path = installer::GetChromeInstallPath(true, dist);
49 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), 49 if (!base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
50 user_exe_path.value()) && 50 user_exe_path.value()) &&
51 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(), 51 !base::FilePath::CompareEqualIgnoreCase(chrome_exe_path.value(),
52 machine_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; 53 return CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY;
59 } 54 }
60 55
61 base::string16 app_guid = installer::GetAppGuidForUpdates( 56 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
62 !InstallUtil::IsPerUserInstall(chrome_exe_path.value().c_str()));
63 DCHECK(!app_guid.empty()); 57 DCHECK(!app_guid.empty());
64 58
65 GoogleUpdateSettings::UpdatePolicy update_policy = 59 GoogleUpdateSettings::UpdatePolicy update_policy =
66 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL); 60 GoogleUpdateSettings::GetAppUpdatePolicy(app_guid, NULL);
67 61
68 if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED) 62 if (update_policy == GoogleUpdateSettings::UPDATES_DISABLED)
69 return GOOGLE_UPDATE_DISABLED_BY_POLICY; 63 return GOOGLE_UPDATE_DISABLED_BY_POLICY;
70 64
71 if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY) 65 if (update_policy == GoogleUpdateSettings::AUTO_UPDATES_ONLY)
72 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY; 66 return GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY;
73 67
74 return GOOGLE_UPDATE_NO_ERROR; 68 return GOOGLE_UPDATE_NO_ERROR;
75 #endif 69 #endif
76 } 70 }
77 71
78 // Creates an instance of a COM Local Server class using either plain vanilla 72 // Creates an instance of a COM Local Server class using either plain vanilla
79 // CoCreateInstance, or using the Elevation moniker if running on Vista. 73 // 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 74 // 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 75 // showing up in the foreground if running on Vista. It can also be NULL if
82 // background UAC prompts are desired. 76 // background UAC prompts are desired.
83 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id, 77 HRESULT CoCreateInstanceAsAdmin(REFCLSID class_id, REFIID interface_id,
84 HWND hwnd, void** interface_ptr) { 78 HWND hwnd, void** interface_ptr) {
85 if (!interface_ptr) 79 if (!interface_ptr)
86 return E_POINTER; 80 return E_POINTER;
87 81
88 // For Vista, need to instantiate the COM server via the elevation 82 // For Vista, need to instantiate the COM server via the elevation
89 // moniker. This ensures that the UAC dialog shows up. 83 // moniker. This ensures that the UAC dialog shows up.
90 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 84 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
91 wchar_t class_id_as_string[MAX_PATH] = {0}; 85 wchar_t class_id_as_string[MAX_PATH] = {};
92 StringFromGUID2(class_id, class_id_as_string, 86 StringFromGUID2(class_id, class_id_as_string,
93 arraysize(class_id_as_string)); 87 arraysize(class_id_as_string));
94 88
95 base::string16 elevation_moniker_name = 89 base::string16 elevation_moniker_name =
96 base::StringPrintf(L"Elevation:Administrator!new:%ls", 90 base::StringPrintf(L"Elevation:Administrator!new:%ls",
97 class_id_as_string); 91 class_id_as_string);
98 92
99 BIND_OPTS3 bind_opts; 93 BIND_OPTS3 bind_opts = {};
100 memset(&bind_opts, 0, sizeof(bind_opts));
101 bind_opts.cbStruct = sizeof(bind_opts); 94 bind_opts.cbStruct = sizeof(bind_opts);
102 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER; 95 bind_opts.dwClassContext = CLSCTX_LOCAL_SERVER;
103 bind_opts.hwnd = hwnd; 96 bind_opts.hwnd = hwnd;
104 97
105 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, 98 return CoGetObject(elevation_moniker_name.c_str(), &bind_opts, interface_id,
106 interface_id, reinterpret_cast<void**>(interface_ptr)); 99 interface_ptr);
107 } 100 }
108 101
109 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, 102 return CoCreateInstance(class_id, NULL, CLSCTX_LOCAL_SERVER, interface_id,
110 interface_id, 103 interface_ptr);
111 reinterpret_cast<void**>(interface_ptr));
112 } 104 }
113 105
106 HRESULT CreateOnDemandAppsClass(
107 bool system_level,
108 bool install_if_newer,
109 HWND elevation_window,
110 base::win::ScopedComPtr<IGoogleUpdate>* on_demand) {
111 if (g_google_update_factory)
112 return g_google_update_factory->Run(on_demand);
114 113
115 } // namespace 114 // For a user-level install, update checks and updates can both be done by a
115 // normal user with the UserAppsClass.
116 if (!system_level)
117 return on_demand->CreateInstance(CLSID_OnDemandUserAppsClass);
118
119 // For a system-level install, update checks can be done by a normal user with
120 // the MachineAppsClass.
121 if (!install_if_newer)
122 return on_demand->CreateInstance(CLSID_OnDemandMachineAppsClass);
123
124 // For a system-level install, an update requires Admin privileges for writing
125 // to %ProgramFiles%. Elevate while instantiating the MachineAppsClass.
126 return CoCreateInstanceAsAdmin(CLSID_OnDemandMachineAppsClass,
127 IID_IGoogleUpdate, elevation_window,
128 on_demand->ReceiveVoid());
129 }
116 130
117 // The GoogleUpdateJobObserver COM class is responsible for receiving status 131 // The GoogleUpdateJobObserver COM class is responsible for receiving status
118 // reports from google Update. It keeps track of the progress as GoogleUpdate 132 // reports from google Update. It keeps track of the progress as Google Update
119 // notifies this observer and ends the message loop that is spinning in once 133 // notifies this observer and runs a completion callback once Google Update
120 // GoogleUpdate reports that it is done. 134 // reports that it is done.
121 class GoogleUpdateJobObserver 135 class GoogleUpdateJobObserver : public CComObjectRootEx<CComSingleThreadModel>,
Peter Kasting 2014/11/26 22:13:05 Nit: Because this file has several classes in it,
grt (UTC plus 2) 2014/11/27 04:44:57 git cl format doesn't like the extra blank line. :
Peter Kasting 2014/11/27 08:07:34 I prefer that people not run git cl format at all.
122 : public CComObjectRootEx<CComSingleThreadModel>, 136 public IJobObserver {
123 public IJobObserver {
124 public: 137 public:
125 BEGIN_COM_MAP(GoogleUpdateJobObserver) 138 BEGIN_COM_MAP(GoogleUpdateJobObserver)
126 COM_INTERFACE_ENTRY(IJobObserver) 139 COM_INTERFACE_ENTRY(IJobObserver)
127 END_COM_MAP() 140 END_COM_MAP()
128 141
129 GoogleUpdateJobObserver() 142 GoogleUpdateJobObserver();
130 : result_(UPGRADE_ERROR) { 143 virtual ~GoogleUpdateJobObserver();
131 }
132 virtual ~GoogleUpdateJobObserver() {}
133 144
134 // Notifications from Google Update: 145 // Sets the callback to be invoked when Google Update reports that the job is
135 STDMETHOD(OnShow)() { 146 // done.
136 return S_OK; 147 void set_on_complete_callback(const base::Closure& on_complete_callback) {
137 } 148 on_complete_callback_ = on_complete_callback;
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 } 149 }
193 150
194 // Returns the results of the update operation. 151 // Returns the results of the update operation.
195 STDMETHOD(GetResult)(GoogleUpdateUpgradeResult* result) { 152 GoogleUpdateUpgradeResult result() const {
196 // Intermediary steps should never be reported to the client. 153 // Intermediary steps should never be reported to the client.
197 DCHECK(result_ != UPGRADE_STARTED && result_ != UPGRADE_CHECK_STARTED); 154 DCHECK_NE(result_, UPGRADE_STARTED);
198 155 DCHECK_NE(result_, UPGRADE_CHECK_STARTED);
Peter Kasting 2014/11/26 22:13:05 Nit: (expected, actual) for DCHECK_NE/EQ
grt (UTC plus 2) 2014/11/27 04:44:57 Is this for consistency with Google Tests's EXPECT
Peter Kasting 2014/11/27 08:07:34 Yes, that's why we instituted that practice. (We
199 *result = result_; 156 return result_;
200 return S_OK;
201 } 157 }
202 158
203 // Returns which version Google Update found on the server (if a more 159 // Returns which version Google Update found on the server (if a more
204 // recent version was found). Otherwise, this will be blank. 160 // recent version was found). Otherwise, this will be blank.
205 STDMETHOD(GetVersionInfo)(base::string16* version_string) { 161 base::string16 new_version() const { return new_version_; }
206 *version_string = new_version_;
207 return S_OK;
208 }
209 162
210 // Returns the Google Update supplied error string that describes the error 163 // Returns the Google Update supplied error string that describes the error
211 // that occurred during the update check/upgrade. 164 // that occurred during the update check/upgrade.
212 STDMETHOD(GetErrorMessage)(base::string16* error_message) { 165 base::string16 error_message() const { return error_message_; }
213 *error_message = error_message_;
214 return S_OK;
215 }
216 166
217 private: 167 private:
168 // IJobObserver:
169 STDMETHOD(OnShow)();
170 STDMETHOD(OnCheckingForUpdate)();
171 STDMETHOD(OnUpdateAvailable)(const TCHAR* version_string);
172 STDMETHOD(OnWaitingToDownload)();
173 STDMETHOD(OnDownloading)(int time_remaining_ms, int pos);
174 STDMETHOD(OnWaitingToInstall)();
175 STDMETHOD(OnInstalling)();
176 STDMETHOD(OnPause)();
177 STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text);
178 STDMETHOD(SetEventSink)(IProgressWndEvents* event_sink);
179
180 // The task runner associated with the thread in which the job runs.
181 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
182
183 // A callback to be run to complete processing;
184 base::Closure on_complete_callback_;
185
218 // The status/result of the Google Update operation. 186 // The status/result of the Google Update operation.
219 GoogleUpdateUpgradeResult result_; 187 GoogleUpdateUpgradeResult result_;
220 188
221 // The version string Google Update found. 189 // The version string Google Update found.
222 base::string16 new_version_; 190 base::string16 new_version_;
223 191
224 // An error message, if any. 192 // An error message, if any.
225 base::string16 error_message_; 193 base::string16 error_message_;
226 194
227 // Allows us control the upgrade process to a small degree. After OnComplete 195 // Allows us control the upgrade process to a small degree. After OnComplete
228 // has been called, this object can not be used. 196 // has been called, this object can not be used.
229 base::win::ScopedComPtr<IProgressWndEvents> event_sink_; 197 base::win::ScopedComPtr<IProgressWndEvents> event_sink_;
198
199 DISALLOW_COPY_AND_ASSIGN(GoogleUpdateJobObserver);
230 }; 200 };
231 201
232 //////////////////////////////////////////////////////////////////////////////// 202 GoogleUpdateJobObserver::GoogleUpdateJobObserver()
233 // GoogleUpdate, public: 203 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
234 204 result_(UPGRADE_ERROR) {
235 GoogleUpdate::GoogleUpdate() 205 }
236 : listener_(NULL) { 206
237 } 207 GoogleUpdateJobObserver::~GoogleUpdateJobObserver() {
238 208 }
239 GoogleUpdate::~GoogleUpdate() { 209
240 } 210 STDMETHODIMP GoogleUpdateJobObserver::OnShow() {
241 211 return S_OK;
242 void GoogleUpdate::CheckForUpdate(bool install_if_newer, HWND window) { 212 }
243 // Need to shunt this request over to InitiateGoogleUpdateCheck and have 213
244 // it run in the file thread. 214 STDMETHODIMP GoogleUpdateJobObserver::OnCheckingForUpdate() {
245 BrowserThread::PostTask( 215 result_ = UPGRADE_CHECK_STARTED;
246 BrowserThread::FILE, FROM_HERE, 216 return S_OK;
247 base::Bind(&GoogleUpdate::InitiateGoogleUpdateCheck, this, 217 }
248 install_if_newer, window, base::MessageLoop::current())); 218
249 } 219 STDMETHODIMP GoogleUpdateJobObserver::OnUpdateAvailable(
250 220 const TCHAR* version_string) {
251 //////////////////////////////////////////////////////////////////////////////// 221 result_ = UPGRADE_IS_AVAILABLE;
252 // GoogleUpdate, private: 222 new_version_ = version_string;
253 223 return S_OK;
254 void GoogleUpdate::InitiateGoogleUpdateCheck(bool install_if_newer, 224 }
255 HWND window, 225
256 base::MessageLoop* main_loop) { 226 STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToDownload() {
227 return S_OK;
228 }
229
230 STDMETHODIMP GoogleUpdateJobObserver::OnDownloading(int time_remaining_ms,
231 int pos) {
232 return S_OK;
233 }
234
235 STDMETHODIMP GoogleUpdateJobObserver::OnWaitingToInstall() {
236 return S_OK;
237 }
238
239 STDMETHODIMP GoogleUpdateJobObserver::OnInstalling() {
240 result_ = UPGRADE_STARTED;
241 return S_OK;
242 }
243
244 STDMETHODIMP GoogleUpdateJobObserver::OnPause() {
245 return S_OK;
246 }
247
248 STDMETHODIMP GoogleUpdateJobObserver::OnComplete(LegacyCompletionCodes code,
249 const TCHAR* text) {
250 if (code == COMPLETION_CODE_ERROR) {
251 error_message_ = text;
252 result_ = UPGRADE_ERROR;
253 } else {
254 // Everything that isn't an error is some form of success. Chrome doesn't
255 // support any of the fancy codes (e.g., COMPLETION_CODE_REBOOT), but they
256 // shouldn't be generated anyway.
257 LOG_IF(DFATAL, (code != COMPLETION_CODE_SUCCESS &&
258 code != COMPLETION_CODE_SUCCESS_CLOSE_UI))
259 << "Unexpected LegacyCompletionCode from IGoogleUpdate: " << code;
260 if (result_ == UPGRADE_STARTED)
261 result_ = UPGRADE_SUCCESSFUL;
262 else if (result_ == UPGRADE_CHECK_STARTED)
263 result_ = UPGRADE_ALREADY_UP_TO_DATE;
264 }
265
266 event_sink_ = NULL;
267
268 task_runner_->PostTask(FROM_HERE, on_complete_callback_);
269 return S_OK;
270 }
271
272 STDMETHODIMP GoogleUpdateJobObserver::SetEventSink(
273 IProgressWndEvents* event_sink) {
274 event_sink_ = event_sink;
275 return S_OK;
276 }
277
278 // A driver that is created and destroyed on the caller's thread and drives
279 // Google Update on another.
280 class UpdateCheckDriver {
281 public:
282 // Runs an update check on |task_runner|, invoking |callback| on the caller's
283 // thread upon completion.
284 static void RunUpdateCheck(const scoped_refptr<base::TaskRunner>& task_runner,
285 bool install_if_newer,
286 HWND elevation_window,
287 const UpdateCheckCallback& callback);
288
289 private:
290 friend class base::DeleteHelper<UpdateCheckDriver>;
291
292 explicit UpdateCheckDriver(const UpdateCheckCallback& callback);
293
294 // Runs the caller's update check callback with the results of the operation.
295 ~UpdateCheckDriver();
296
297 // Starts an update check.
298 void BeginUpdateCheck(bool install_if_newer, HWND elevation_window);
299
300 // Helper function for starting an update check. Returns true if the check was
301 // properly started, in which case CompleteUpdateCheck will be invoked upon
302 // completion to return results to the caller on its own thread.
303 bool BeginUpdateCheckInternal(bool install_if_newer, HWND elevation_window);
304
305 // Invoked when results are in from Google Update.
306 void CompleteUpdateCheck();
307
308 // Prepares |results| to return the upgrade error indicated by |error_code|
309 // and |hr|. The string " -- system level" is included in the generated error
310 // message when |system_level| is true.
311 void OnUpgradeError(GoogleUpdateErrorCode error_code,
312 HRESULT hr,
313 bool system_level);
314
315 // The caller's task runner, on which |result_callback_| will be run.
316 scoped_refptr<base::SingleThreadTaskRunner> result_runner_;
317
318 // The caller's callback to be run when the update check is compelte.
319 UpdateCheckCallback result_callback_;
320
321 // The results of the update check.
322 GoogleUpdateUpgradeResult result_;
323 GoogleUpdateErrorCode error_code_;
324 base::string16 error_message_;
325 base::string16 version_;
326 HRESULT hresult_;
327
328 // A direct pointer to the job observer by which the driver is notified of
329 // interesting events from Google Update.
330 CComObject<GoogleUpdateJobObserver>* job_observer_;
331
332 // A scoped pointer to |job_observer_| that holds a reference to it, keeping
333 // it alive.
334 base::win::ScopedComPtr<IJobObserver> job_holder_;
335
336 // The on-demand updater that is doing the work.
337 base::win::ScopedComPtr<IGoogleUpdate> on_demand_;
338
339 DISALLOW_COPY_AND_ASSIGN(UpdateCheckDriver);
340 };
341
342 // static
343 void UpdateCheckDriver::RunUpdateCheck(
344 const scoped_refptr<base::TaskRunner>& task_runner,
345 bool install_if_newer,
346 HWND elevation_window,
347 const UpdateCheckCallback& callback) {
348 // The driver is owned by itself, and will self-destruct when its work is
349 // done.
350 UpdateCheckDriver* driver = new UpdateCheckDriver(callback);
351 task_runner->PostTask(
352 FROM_HERE,
353 base::Bind(&UpdateCheckDriver::BeginUpdateCheck, base::Unretained(driver),
354 install_if_newer, elevation_window));
355 }
356
357 // Runs on the caller's thread.
358 UpdateCheckDriver::UpdateCheckDriver(const UpdateCheckCallback& callback)
359 : result_runner_(base::ThreadTaskRunnerHandle::Get()),
360 result_callback_(callback),
361 result_(UPGRADE_ERROR),
362 error_code_(GOOGLE_UPDATE_NO_ERROR),
363 hresult_(S_OK),
364 job_observer_(nullptr) {
365 }
366
367 UpdateCheckDriver::~UpdateCheckDriver() {
368 DCHECK(result_runner_->BelongsToCurrentThread());
369 // If there is an error, then error_code must not be blank, and vice versa.
370 DCHECK_NE(result_ != UPGRADE_ERROR, error_code_ != GOOGLE_UPDATE_NO_ERROR);
Peter Kasting 2014/11/26 22:13:05 Nit: Please flip the "!="s to "=="s ... trying to
grt (UTC plus 2) 2014/11/27 04:44:57 Oops. I mis-read your previous comment. I wondered
371 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpgradeResult", result_,
372 NUM_UPGRADE_RESULTS);
373 if (result_ == UPGRADE_ERROR) {
374 UMA_HISTOGRAM_ENUMERATION("GoogleUpdate.UpdateErrorCode", error_code_,
375 NUM_ERROR_CODES);
376 if (hresult_ != S_OK)
377 UMA_HISTOGRAM_SPARSE_SLOWLY("GoogleUpdate.ErrorHresult", hresult_);
378 }
379 result_callback_.Run(result_, error_code_, error_message_, version_);
380 }
381
382 void UpdateCheckDriver::BeginUpdateCheck(bool install_if_newer,
383 HWND elevation_window) {
384 // Return results immediately if the driver is not waiting for Google Update.
385 if (!BeginUpdateCheckInternal(install_if_newer, elevation_window))
386 result_runner_->DeleteSoon(FROM_HERE, this);
387 }
388
389 bool UpdateCheckDriver::BeginUpdateCheckInternal(bool install_if_newer,
390 HWND elevation_window) {
257 base::FilePath chrome_exe; 391 base::FilePath chrome_exe;
258 if (!PathService::Get(base::DIR_EXE, &chrome_exe)) 392 if (!PathService::Get(base::DIR_EXE, &chrome_exe))
259 NOTREACHED(); 393 NOTREACHED();
260 394
261 GoogleUpdateErrorCode error_code = CanUpdateCurrentChrome(chrome_exe); 395 const bool system_level =
262 if (error_code != GOOGLE_UPDATE_NO_ERROR) { 396 !InstallUtil::IsPerUserInstall(chrome_exe.value().c_str());
263 main_loop->PostTask( 397
264 FROM_HERE, 398 // The failures handled here are:
265 base::Bind(&GoogleUpdate::ReportResults, this, 399 // CANNOT_UPGRADE_CHROME_IN_THIS_DIRECTORY,
266 UPGRADE_ERROR, error_code, base::string16())); 400 // GOOGLE_UPDATE_DISABLED_BY_POLICY, and
267 return; 401 // GOOGLE_UPDATE_DISABLED_BY_POLICY_AUTO_ONLY.
402 error_code_ = CanUpdateCurrentChrome(chrome_exe, system_level);
403 if (error_code_ != GOOGLE_UPDATE_NO_ERROR) {
404 // These failures are handled in the UX with custom messages.
405 result_ = UPGRADE_ERROR;
406 return false;
268 } 407 }
269 408
270 // Make sure ATL is initialized in this module. 409 // Make sure ATL is initialized in this module.
271 ui::win::CreateATLModuleIfNeeded(); 410 ui::win::CreateATLModuleIfNeeded();
272 411
273 CComObject<GoogleUpdateJobObserver>* job_observer;
274 HRESULT hr = 412 HRESULT hr =
275 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer); 413 CComObject<GoogleUpdateJobObserver>::CreateInstance(&job_observer_);
276 if (hr != S_OK) { 414 if (hr != S_OK) {
277 // Most of the error messages come straight from Google Update. This one is 415 // Most of the error messages come straight from Google Update. This one is
278 // deemed worthy enough to also warrant its own error. 416 // deemed worthy enough to also warrant its own error.
279 GoogleUpdateErrorCode error = GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED; 417 OnUpgradeError(GOOGLE_UPDATE_JOB_SERVER_CREATION_FAILED, hr, false);
280 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 418 return false;
281 ReportFailure( 419 }
282 hr, error, 420 // Hold a reference on the observer for the lifetime of the driver.
283 l10n_util::GetStringFUTF16(IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 421 job_holder_ = job_observer_;
284 error_code), 422
285 main_loop); 423 job_observer_->set_on_complete_callback(base::Bind(
286 return; 424 &UpdateCheckDriver::CompleteUpdateCheck, base::Unretained(this)));
287 } 425
288 426 hr = CreateOnDemandAppsClass(system_level, install_if_newer, elevation_window,
289 base::win::ScopedComPtr<IJobObserver> job_holder(job_observer); 427 &on_demand_);
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) { 428 if (hr != S_OK) {
312 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND; 429 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_NOT_FOUND, hr, system_level);
313 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 430 return false;
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 } 431 }
323 432
324 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level); 433 base::string16 app_guid = installer::GetAppGuidForUpdates(system_level);
325 DCHECK(!app_guid.empty()); 434 DCHECK(!app_guid.empty());
326 435
327 if (!install_if_newer) 436 if (install_if_newer)
328 hr = on_demand->CheckForUpdate(app_guid.c_str(), job_observer); 437 hr = on_demand_->Update(app_guid.c_str(), job_observer_);
329 else 438 else
330 hr = on_demand->Update(app_guid.c_str(), job_observer); 439 hr = on_demand_->CheckForUpdate(app_guid.c_str(), job_observer_);
331 440
332 if (hr != S_OK) { 441 if (hr != S_OK) {
333 GoogleUpdateErrorCode error = GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR; 442 OnUpgradeError(GOOGLE_UPDATE_ONDEMAND_CLASS_REPORTED_ERROR, hr,
334 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 443 system_level);
335 ReportFailure(hr, error, 444 return false;
336 l10n_util::GetStringFUTF16( 445 }
337 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 446 return true;
338 error_code), 447 }
339 main_loop); 448
340 return; 449 void UpdateCheckDriver::CompleteUpdateCheck() {
341 } 450 result_ = job_observer_->result();
342 451 if (result_ == UPGRADE_ERROR) {
343 // Need to spin the message loop while Google Update is running so that it 452 error_code_ = GOOGLE_UPDATE_ERROR_UPDATING;
344 // can report back to us through GoogleUpdateJobObserver. This message loop 453 error_message_ = job_observer_->error_message();
345 // will terminate once Google Update sends us the completion status 454 } else {
346 // (success/error). See OnComplete(). 455 version_ = job_observer_->new_version();
347 base::MessageLoop::current()->Run(); 456 }
348 457 // Release the reference on the COM objects.
349 GoogleUpdateUpgradeResult results; 458 on_demand_ = nullptr;
350 hr = job_observer->GetResult(&results); 459 job_observer_ = nullptr;
351 460 job_holder_ = nullptr;
352 if (hr != S_OK) { 461
353 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_RESULT_CALL_FAILED; 462 result_runner_->DeleteSoon(FROM_HERE, this);
354 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 463 }
355 ReportFailure(hr, error, 464
356 l10n_util::GetStringFUTF16( 465 void UpdateCheckDriver::OnUpgradeError(GoogleUpdateErrorCode error_code,
357 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 466 HRESULT hr,
358 error_code), 467 bool system_level) {
359 main_loop); 468 result_ = UPGRADE_ERROR;
360 return; 469 error_code_ = error_code;
361 } 470 hresult_ = hr;
362 471 base::string16 error_msg =
363 if (results == UPGRADE_ERROR) { 472 base::StringPrintf(L"%d: 0x%x", error_code_, hresult_);
364 base::string16 error_message; 473 if (system_level)
365 job_observer->GetErrorMessage(&error_message); 474 error_msg += L" -- system level";
366 ReportFailure(hr, GOOGLE_UPDATE_ERROR_UPDATING, error_message, main_loop); 475 error_message_ = l10n_util::GetStringFUTF16(
367 return; 476 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, error_msg);
368 } 477 }
369 478
370 hr = job_observer->GetVersionInfo(&version_available_); 479 } // namespace
371 if (hr != S_OK) { 480
372 GoogleUpdateErrorCode error = GOOGLE_UPDATE_GET_VERSION_INFO_FAILED; 481 void CheckForUpdate(bool install_if_newer,
373 base::string16 error_code = base::StringPrintf(L"%d: 0x%x", error, hr); 482 HWND elevation_window,
374 ReportFailure(hr, error, 483 const UpdateCheckCallback& callback) {
375 l10n_util::GetStringFUTF16( 484 scoped_refptr<base::TaskRunner> task_runner(
376 IDS_ABOUT_BOX_ERROR_UPDATE_CHECK_FAILED, 485 content::BrowserThread::GetMessageLoopProxyForThread(
377 error_code), 486 content::BrowserThread::FILE));
378 main_loop); 487
379 return; 488 internal::CheckForUpdate(task_runner, install_if_newer, elevation_window,
380 } 489 callback);
381 490 }
382 main_loop->PostTask( 491
383 FROM_HERE, 492 namespace internal {
384 base::Bind(&GoogleUpdate::ReportResults, this, 493
385 results, GOOGLE_UPDATE_NO_ERROR, base::string16())); 494 void SetGoogleUpdateFactory(
386 job_holder = NULL; 495 const OnDemandAppsClassFactory& google_update_factory) {
387 on_demand = NULL; 496 if (g_google_update_factory) {
388 } 497 delete g_google_update_factory;
389 498 g_google_update_factory = nullptr;
390 void GoogleUpdate::ReportResults(GoogleUpdateUpgradeResult results, 499 }
391 GoogleUpdateErrorCode error_code, 500 if (!google_update_factory.is_null()) {
392 const base::string16& error_message) { 501 g_google_update_factory =
393 // If there is an error, then error code must not be blank, and vice versa. 502 new OnDemandAppsClassFactory(google_update_factory);
394 DCHECK(results == UPGRADE_ERROR ? error_code != GOOGLE_UPDATE_NO_ERROR : 503 }
395 error_code == GOOGLE_UPDATE_NO_ERROR); 504 }
396 UMA_HISTOGRAM_ENUMERATION( 505
397 "GoogleUpdate.UpgradeResult", results, NUM_UPGRADE_RESULTS); 506 void CheckForUpdate(const scoped_refptr<base::TaskRunner>& task_runner,
398 if (results == UPGRADE_ERROR) { 507 bool install_if_newer,
399 UMA_HISTOGRAM_ENUMERATION( 508 HWND elevation_window,
400 "GoogleUpdate.UpdateErrorCode", error_code, NUM_ERROR_CODES); 509 const UpdateCheckCallback& callback) {
401 } 510 UpdateCheckDriver::RunUpdateCheck(task_runner, install_if_newer,
402 if (listener_) { 511 elevation_window, callback);
403 listener_->OnReportResults( 512 }
404 results, error_code, error_message, version_available_); 513
405 } 514 } // namespace internal
406 }
407
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698