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

Side by Side Diff: remoting/host/plugin/daemon_installer_win.cc

Issue 10021003: Implemented on-demand installation of the Chromoting Host on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CR feedback Created 8 years, 8 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 "remoting/host/plugin/daemon_installer_win.h"
6
7 #include <windows.h>
8
9 #include "base/bind.h"
10 #include "base/message_loop.h"
11 #include "base/process_util.h"
12 #include "base/string16.h"
13 #include "base/stringize_macros.h"
14 #include "base/stringprintf.h"
15 #include "base/time.h"
16 #include "base/timer.h"
17 #include "base/win/object_watcher.h"
18 #include "base/win/registry.h"
19 #include "base/win/scoped_bstr.h"
20 #include "base/win/scoped_comptr.h"
21 #include "base/win/scoped_handle.h"
22
23 namespace omaha {
24 #include "google_update/google_update_idl.h"
25 } // namespace omaha
Sergey Ulanov 2012/04/09 22:32:58 nit: two spaces before the comment
alexeypa (please no reviews) 2012/04/10 00:20:06 Done.
26
27 using base::win::ScopedBstr;
28 using base::win::ScopedComPtr;
29
30 namespace {
31
32 // The COM elevation moniker for Omaha.
33 const char16 kOmahaElevationMoniker[] =
34 TO_L_STRING("Elevation:Administrator!new:GoogleUpdate.Update3WebMachine");
35
36 // The registry key where the configuration of Omaha is stored.
37 const char16 kOmahaUpdateKeyName[] = TO_L_STRING("Software\\Google\\Update");
38
39 // The name of the value where the full path to GoogleUpdate.exe is stored.
40 const char16 kOmahaPathValueName[] = TO_L_STRING("path");
41
42 // The command line format string for GoogleUpdate.exe
43 const char16 kGoogleUpdateCommandLineFormat[] =
44 TO_L_STRING("\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&")
45 TO_L_STRING("appname=Chromoting%%20Host&needsadmin=True&lang=%ls\"");
46
47 // The Omaha Appid of the host.
48 const char16 kOmahaAppid[] =
49 TO_L_STRING("{b210701e-ffc4-49e3-932b-370728c72662}");
50
51 // TODO(alexeypa): Get the desired laungage from the web app.
52 const char16 kOmahaLanguage[] = TO_L_STRING("en");
53
54 // An empty string for optional parameters.
55 const char16 kOmahaEmpty[] = TO_L_STRING("");
56
57 // The installation status polling interval.
58 const int kOmahaPollIntervalMs = 500;
59
60 } // namespace
61
62 namespace remoting {
63
64 // This class implements on-demand installation of the Chromoting Host via
65 // per-machine Omaha instance.
66 class DaemonComInstallerWin : public DaemonInstallerWin {
67 public:
68 DaemonComInstallerWin(const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3,
69 const CompletionCallback& done);
70
71 // DaemonInstallerWin implementation.
72 virtual void Install() OVERRIDE;
73
74 private:
75 // Polls the installation status performing state-specific actions (such as
76 // starting installation once download has finished).
77 void PollInstallationStatus();
78
79 // Omaha interfaces.
80 ScopedComPtr<omaha::IAppWeb> app_;
81 ScopedComPtr<omaha::IAppBundleWeb> bundle_;
82 ScopedComPtr<omaha::IGoogleUpdate3Web> update3_;
83
84 base::DelayTimer<DaemonComInstallerWin> polling_timer_;
Sergey Ulanov 2012/04/09 22:32:58 Why DelayTimer instead of RepeatingTimer? Or you c
alexeypa (please no reviews) 2012/04/10 00:20:06 RepeatingTimer has to be stopped explicitly, so I'
Sergey Ulanov 2012/04/10 01:17:14 Hm, then maybe use base::Timer? It's not a templat
85 };
86
87 // This class implements on-demand installation of the Chromoting Host by
88 // launching a per-user instance of Omaha and requesting elevation.
89 class DaemonCommandLineInstallerWin
90 : public DaemonInstallerWin,
91 public base::win::ObjectWatcher::Delegate {
92 public:
93 DaemonCommandLineInstallerWin(const CompletionCallback& done);
94 ~DaemonCommandLineInstallerWin();
95
96 // DaemonInstallerWin implementation.
97 virtual void Install() OVERRIDE;
98
99 // base::win::ObjectWatcher::Delegate implementation.
100 virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
101
102 private:
103 // Handle of the launched process.
104 base::win::ScopedHandle process_;
105
106 // Used to determine when the launched process terminates.
107 base::win::ObjectWatcher process_watcher_;
108 };
109
110 DaemonComInstallerWin::DaemonComInstallerWin(
111 const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3,
112 const CompletionCallback& done)
113 : DaemonInstallerWin(done),
114 update3_(update3),
115 ALLOW_THIS_IN_INITIALIZER_LIST(
116 polling_timer_(
117 FROM_HERE,
118 base::TimeDelta::FromMilliseconds(kOmahaPollIntervalMs),
119 this,
120 &DaemonComInstallerWin::PollInstallationStatus)) {
121 }
122
123 void DaemonComInstallerWin::Install() {
124 // Create an app bundle.
125 ScopedComPtr<IDispatch> dispatch;
126 HRESULT hr = update3_->createAppBundleWeb(dispatch.Receive());
127 if (FAILED(hr)) {
128 Done(hr);
129 return;
130 }
131
132 hr = dispatch.QueryInterface(omaha::IID_IAppBundleWeb, bundle_.ReceiveVoid());
133 if (FAILED(hr)) {
134 Done(hr);
135 return;
136 }
137
138 hr = bundle_->initialize();
139 if (FAILED(hr)) {
140 Done(hr);
141 return;
142 }
143
144 // Add Chromoting Host to the bundle.
145 ScopedBstr appid(kOmahaAppid);
146 ScopedBstr empty(kOmahaEmpty);
147 ScopedBstr language(kOmahaLanguage);
148 hr = bundle_->createApp(appid, empty, language, empty);
149 if (FAILED(hr)) {
150 Done(hr);
151 return;
152 }
153
154 hr = bundle_->checkForUpdate();
155 if (FAILED(hr)) {
156 Done(hr);
157 return;
158 }
159
160 dispatch.Release();
161 hr = bundle_->get_appWeb(0, dispatch.Receive());
162 if (FAILED(hr)) {
163 Done(hr);
164 return;
165 }
166
167 hr = dispatch.QueryInterface(omaha::IID_IAppWeb,
168 app_.ReceiveVoid());
169 if (FAILED(hr)) {
170 Done(hr);
171 return;
172 }
173
174 // Now poll for the installation status.
175 PollInstallationStatus();
176 }
177
178 void DaemonComInstallerWin::PollInstallationStatus() {
179 // Get the current application installation state.
180 // N.B. The object underlying the ICurrentState interface has static data that
181 // does not get updated as the server state changes. To get the most "current"
182 // state, the currentState property needs to be queried again.
183 ScopedComPtr<IDispatch> dispatch;
184 HRESULT hr = app_->get_currentState(dispatch.Receive());
185 if (FAILED(hr)) {
186 Done(hr);
187 return;
188 }
189
190 ScopedComPtr<omaha::ICurrentState> current_state;
191 hr = dispatch.QueryInterface(omaha::IID_ICurrentState,
192 current_state.ReceiveVoid());
193 if (FAILED(hr)) {
194 Done(hr);
195 return;
196 }
197
198 LONG state;
199 hr = current_state->get_stateValue(&state);
200 if (FAILED(hr)) {
201 Done(hr);
202 return;
203 }
204
205 // Perform state-specific actions.
206 switch (state) {
207 case omaha::STATE_INIT:
208 case omaha::STATE_WAITING_TO_CHECK_FOR_UPDATE:
209 case omaha::STATE_CHECKING_FOR_UPDATE:
210 case omaha::STATE_WAITING_TO_DOWNLOAD:
211 case omaha::STATE_RETRYING_DOWNLOAD:
212 case omaha::STATE_DOWNLOADING:
213 case omaha::STATE_WAITING_TO_INSTALL:
214 case omaha::STATE_INSTALLING:
215 case omaha::STATE_PAUSED:
216 break;
217
218 case omaha::STATE_UPDATE_AVAILABLE:
219 hr = bundle_->download();
220 if (FAILED(hr)) {
221 Done(hr);
222 return;
223 }
224 break;
225
226 case omaha::STATE_DOWNLOAD_COMPLETE:
227 case omaha::STATE_EXTRACTING:
228 case omaha::STATE_APPLYING_DIFFERENTIAL_PATCH:
229 case omaha::STATE_READY_TO_INSTALL:
230 hr = bundle_->install();
231 if (FAILED(hr)) {
232 Done(hr);
233 return;
234 }
235 break;
236
237 case omaha::STATE_INSTALL_COMPLETE:
238 case omaha::STATE_NO_UPDATE:
239 // Installation complete or not required. Report success.
240 Done(S_OK);
241 return;
242
243 case omaha::STATE_ERROR: {
244 HRESULT error_code;
245 hr = current_state->get_errorCode(&error_code);
246 if (FAILED(hr)) {
247 error_code = hr;
248 }
249 Done(error_code);
250 return;
251 }
252
253 default:
254 LOG(ERROR) << "Unknown bundle state: " << state << ".";
255 Done(E_FAIL);
256 return;
257 }
258
259 // Keep polling.
260 polling_timer_.Reset();
261 }
262
263 DaemonCommandLineInstallerWin::DaemonCommandLineInstallerWin(
264 const CompletionCallback& done) : DaemonInstallerWin(done) {
265 }
266
267 DaemonCommandLineInstallerWin::~DaemonCommandLineInstallerWin() {
268 process_watcher_.StopWatching();
269 }
270
271 void DaemonCommandLineInstallerWin::Install() {
272 // Get the full path to GoogleUpdate.exe from the registry.
273 base::win::RegKey update_key;
274 LONG result = update_key.Open(HKEY_CURRENT_USER,
275 kOmahaUpdateKeyName,
276 KEY_READ);
277 if (result != ERROR_SUCCESS) {
278 Done(HRESULT_FROM_WIN32(result));
279 return;
280 }
281
282 string16 google_update;
283 result = update_key.ReadValue(kOmahaPathValueName,
284 &google_update);
285 if (result != ERROR_SUCCESS) {
286 Done(HRESULT_FROM_WIN32(result));
287 return;
288 }
289
290 // Launch the updater process and wait for its termination.
291 string16 command_line =
292 StringPrintf(kGoogleUpdateCommandLineFormat,
293 google_update.c_str(),
294 kOmahaAppid,
295 kOmahaLanguage);
296
297 base::LaunchOptions options;
298 if (!base::LaunchProcess(command_line, options, process_.Receive())) {
299 result = GetLastError();
300 Done(HRESULT_FROM_WIN32(result));
301 return;
302 }
303
304 if (!process_watcher_.StartWatching(process_.Get(), this)) {
305 result = GetLastError();
306 Done(HRESULT_FROM_WIN32(result));
307 return;
308 }
309 }
310
311 void DaemonCommandLineInstallerWin::OnObjectSignaled(HANDLE object) {
312 // Check if the updater process returned success.
313 DWORD exit_code;
314 if (GetExitCodeProcess(process_.Get(), &exit_code) && exit_code == 0) {
315 Done(S_OK);
316 } else {
317 Done(E_FAIL);
318 }
319 }
320
321 DaemonInstallerWin::DaemonInstallerWin(const CompletionCallback& done)
322 : done_(done) {
323 }
324
325 DaemonInstallerWin::~DaemonInstallerWin() {
326 }
327
328 void DaemonInstallerWin::Done(HRESULT result) {
329 done_.Run(result);
330 }
331
332 // static
333 scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create(
334 CompletionCallback done) {
335 // Check if the machine instance of Omaha is available.
336 BIND_OPTS3 bind_options;
337 memset(&bind_options, 0, sizeof(bind_options));
338 bind_options.cbStruct = sizeof(bind_options);
339 bind_options.hwnd = NULL;
340 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER;
341
342 ScopedComPtr<omaha::IGoogleUpdate3Web> update3;
343 HRESULT result = ::CoGetObject(
344 kOmahaElevationMoniker,
345 &bind_options,
346 omaha::IID_IGoogleUpdate3Web,
347 update3.ReceiveVoid());
348 if (SUCCEEDED(result)) {
349 // The machine instance of Omaha is available and we successfully passed
350 // the UAC prompt.
351 return scoped_ptr<DaemonInstallerWin>(
352 new DaemonComInstallerWin(update3, done));
353 } else if (result == CO_E_CLASSSTRING) {
354 // The machine instance of Omaha is not available so we will have to run
355 // GoogleUpdate.exe manually passing "needsadmin=True". This will cause
356 // Omaha to install the machine instance first and then install Chromoting
357 // Host.
358 return scoped_ptr<DaemonInstallerWin>(
359 new DaemonCommandLineInstallerWin(done));
360 } else {
361 // The user declined the UAC prompt or some other error occured.
362 done.Run(result);
363 return scoped_ptr<DaemonInstallerWin>();
364 }
365 }
366
367 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698