OLD | NEW |
---|---|
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 } | |
OLD | NEW |