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

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: The last piece of CR feeback. Rebased. 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
« no previous file with comments | « remoting/host/plugin/daemon_installer_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
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::Timer polling_timer_;
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 base::Bind(&DaemonComInstallerWin::PollInstallationStatus,
120 base::Unretained(this)),
121 false)) {
122 }
123
124 void DaemonComInstallerWin::Install() {
125 // Create an app bundle.
126 ScopedComPtr<IDispatch> dispatch;
127 HRESULT hr = update3_->createAppBundleWeb(dispatch.Receive());
128 if (FAILED(hr)) {
129 Done(hr);
130 return;
131 }
132
133 hr = dispatch.QueryInterface(omaha::IID_IAppBundleWeb, bundle_.ReceiveVoid());
134 if (FAILED(hr)) {
135 Done(hr);
136 return;
137 }
138
139 hr = bundle_->initialize();
140 if (FAILED(hr)) {
141 Done(hr);
142 return;
143 }
144
145 // Add Chromoting Host to the bundle.
146 ScopedBstr appid(kOmahaAppid);
147 ScopedBstr empty(kOmahaEmpty);
148 ScopedBstr language(kOmahaLanguage);
149 hr = bundle_->createApp(appid, empty, language, empty);
150 if (FAILED(hr)) {
151 Done(hr);
152 return;
153 }
154
155 hr = bundle_->checkForUpdate();
156 if (FAILED(hr)) {
157 Done(hr);
158 return;
159 }
160
161 dispatch.Release();
162 hr = bundle_->get_appWeb(0, dispatch.Receive());
163 if (FAILED(hr)) {
164 Done(hr);
165 return;
166 }
167
168 hr = dispatch.QueryInterface(omaha::IID_IAppWeb,
169 app_.ReceiveVoid());
170 if (FAILED(hr)) {
171 Done(hr);
172 return;
173 }
174
175 // Now poll for the installation status.
176 PollInstallationStatus();
177 }
178
179 void DaemonComInstallerWin::PollInstallationStatus() {
180 // Get the current application installation state.
181 // N.B. The object underlying the ICurrentState interface has static data that
182 // does not get updated as the server state changes. To get the most "current"
183 // state, the currentState property needs to be queried again.
184 ScopedComPtr<IDispatch> dispatch;
185 HRESULT hr = app_->get_currentState(dispatch.Receive());
186 if (FAILED(hr)) {
187 Done(hr);
188 return;
189 }
190
191 ScopedComPtr<omaha::ICurrentState> current_state;
192 hr = dispatch.QueryInterface(omaha::IID_ICurrentState,
193 current_state.ReceiveVoid());
194 if (FAILED(hr)) {
195 Done(hr);
196 return;
197 }
198
199 LONG state;
200 hr = current_state->get_stateValue(&state);
201 if (FAILED(hr)) {
202 Done(hr);
203 return;
204 }
205
206 // Perform state-specific actions.
207 switch (state) {
208 case omaha::STATE_INIT:
209 case omaha::STATE_WAITING_TO_CHECK_FOR_UPDATE:
210 case omaha::STATE_CHECKING_FOR_UPDATE:
211 case omaha::STATE_WAITING_TO_DOWNLOAD:
212 case omaha::STATE_RETRYING_DOWNLOAD:
213 case omaha::STATE_DOWNLOADING:
214 case omaha::STATE_WAITING_TO_INSTALL:
215 case omaha::STATE_INSTALLING:
216 case omaha::STATE_PAUSED:
217 break;
218
219 case omaha::STATE_UPDATE_AVAILABLE:
220 hr = bundle_->download();
221 if (FAILED(hr)) {
222 Done(hr);
223 return;
224 }
225 break;
226
227 case omaha::STATE_DOWNLOAD_COMPLETE:
228 case omaha::STATE_EXTRACTING:
229 case omaha::STATE_APPLYING_DIFFERENTIAL_PATCH:
230 case omaha::STATE_READY_TO_INSTALL:
231 hr = bundle_->install();
232 if (FAILED(hr)) {
233 Done(hr);
234 return;
235 }
236 break;
237
238 case omaha::STATE_INSTALL_COMPLETE:
239 case omaha::STATE_NO_UPDATE:
240 // Installation complete or not required. Report success.
241 Done(S_OK);
242 return;
243
244 case omaha::STATE_ERROR: {
245 HRESULT error_code;
246 hr = current_state->get_errorCode(&error_code);
247 if (FAILED(hr)) {
248 error_code = hr;
249 }
250 Done(error_code);
251 return;
252 }
253
254 default:
255 LOG(ERROR) << "Unknown bundle state: " << state << ".";
256 Done(E_FAIL);
257 return;
258 }
259
260 // Keep polling.
261 polling_timer_.Reset();
262 }
263
264 DaemonCommandLineInstallerWin::DaemonCommandLineInstallerWin(
265 const CompletionCallback& done) : DaemonInstallerWin(done) {
266 }
267
268 DaemonCommandLineInstallerWin::~DaemonCommandLineInstallerWin() {
269 process_watcher_.StopWatching();
270 }
271
272 void DaemonCommandLineInstallerWin::Install() {
273 // Get the full path to GoogleUpdate.exe from the registry.
274 base::win::RegKey update_key;
275 LONG result = update_key.Open(HKEY_CURRENT_USER,
276 kOmahaUpdateKeyName,
277 KEY_READ);
278 if (result != ERROR_SUCCESS) {
279 Done(HRESULT_FROM_WIN32(result));
280 return;
281 }
282
283 string16 google_update;
284 result = update_key.ReadValue(kOmahaPathValueName,
285 &google_update);
286 if (result != ERROR_SUCCESS) {
287 Done(HRESULT_FROM_WIN32(result));
288 return;
289 }
290
291 // Launch the updater process and wait for its termination.
292 string16 command_line =
293 StringPrintf(kGoogleUpdateCommandLineFormat,
294 google_update.c_str(),
295 kOmahaAppid,
296 kOmahaLanguage);
297
298 base::LaunchOptions options;
299 if (!base::LaunchProcess(command_line, options, process_.Receive())) {
300 result = GetLastError();
301 Done(HRESULT_FROM_WIN32(result));
302 return;
303 }
304
305 if (!process_watcher_.StartWatching(process_.Get(), this)) {
306 result = GetLastError();
307 Done(HRESULT_FROM_WIN32(result));
308 return;
309 }
310 }
311
312 void DaemonCommandLineInstallerWin::OnObjectSignaled(HANDLE object) {
313 // Check if the updater process returned success.
314 DWORD exit_code;
315 if (GetExitCodeProcess(process_.Get(), &exit_code) && exit_code == 0) {
316 Done(S_OK);
317 } else {
318 Done(E_FAIL);
319 }
320 }
321
322 DaemonInstallerWin::DaemonInstallerWin(const CompletionCallback& done)
323 : done_(done) {
324 }
325
326 DaemonInstallerWin::~DaemonInstallerWin() {
327 }
328
329 void DaemonInstallerWin::Done(HRESULT result) {
330 done_.Run(result);
331 }
332
333 // static
334 scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create(
335 CompletionCallback done) {
336 // Check if the machine instance of Omaha is available.
337 BIND_OPTS3 bind_options;
338 memset(&bind_options, 0, sizeof(bind_options));
339 bind_options.cbStruct = sizeof(bind_options);
340 bind_options.hwnd = NULL;
341 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER;
342
343 ScopedComPtr<omaha::IGoogleUpdate3Web> update3;
344 HRESULT result = ::CoGetObject(
345 kOmahaElevationMoniker,
346 &bind_options,
347 omaha::IID_IGoogleUpdate3Web,
348 update3.ReceiveVoid());
349 if (SUCCEEDED(result)) {
350 // The machine instance of Omaha is available and we successfully passed
351 // the UAC prompt.
352 return scoped_ptr<DaemonInstallerWin>(
353 new DaemonComInstallerWin(update3, done));
354 } else if (result == CO_E_CLASSSTRING) {
355 // The machine instance of Omaha is not available so we will have to run
356 // GoogleUpdate.exe manually passing "needsadmin=True". This will cause
357 // Omaha to install the machine instance first and then install Chromoting
358 // Host.
359 return scoped_ptr<DaemonInstallerWin>(
360 new DaemonCommandLineInstallerWin(done));
361 } else {
362 // The user declined the UAC prompt or some other error occured.
363 done.Run(result);
364 return scoped_ptr<DaemonInstallerWin>();
365 }
366 }
367
368 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/plugin/daemon_installer_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698