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

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

Issue 873353004: Remove InstallHost from the DaemonController. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 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
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/setup/daemon_installer_win.h"
6
7 #include <windows.h>
8
9 #include "base/bind.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/process/launch.h"
12 #include "base/strings/string16.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "base/timer/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 #include "base/win/scoped_variant.h"
23 #include "base/win/windows_version.h"
24 #include "google_update/google_update_idl.h"
25 #include "remoting/base/dispatch_win.h"
26 #include "remoting/host/win/omaha.h"
27
28 using base::win::ScopedBstr;
29 using base::win::ScopedComPtr;
30 using base::win::ScopedVariant;
31
32 namespace {
33
34 // ProgID of the per-machine Omaha COM server.
35 const wchar_t kGoogleUpdate[] = L"GoogleUpdate.Update3WebMachine";
36
37 // The COM elevation moniker for the per-machine Omaha COM server.
38 const wchar_t kGoogleUpdateElevationMoniker[] =
39 L"Elevation:Administrator!new:GoogleUpdate.Update3WebMachine";
40
41 // The registry key where the configuration of Omaha is stored.
42 const wchar_t kOmahaUpdateKeyName[] = L"Software\\Google\\Update";
43
44 // The name of the value where the full path to GoogleUpdate.exe is stored.
45 const wchar_t kOmahaPathValueName[] = L"path";
46
47 // The command line format string for GoogleUpdate.exe
48 const wchar_t kGoogleUpdateCommandLineFormat[] =
49 L"\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&"
50 L"appname=Chromoting%%20Host&needsadmin=True&lang=%ls\"";
51
52 // TODO(alexeypa): Get the desired laungage from the web app.
53 const wchar_t kOmahaLanguage[] = L"en";
54
55 // An empty string for optional parameters.
56 const wchar_t kOmahaEmpty[] = L"";
57
58 // The installation status polling interval.
59 const int kOmahaPollIntervalMs = 500;
60
61 } // namespace
62
63 namespace remoting {
64
65 // This class implements on-demand installation of the Chromoting Host via
66 // per-machine Omaha instance.
67 class DaemonComInstallerWin : public DaemonInstallerWin {
68 public:
69 DaemonComInstallerWin(const ScopedComPtr<IDispatch>& update3,
70 const CompletionCallback& done);
71
72 // DaemonInstallerWin implementation.
73 virtual void Install() override;
74
75 private:
76 // Polls the installation status performing state-specific actions (such as
77 // starting installation once download has finished).
78 void PollInstallationStatus();
79
80 // Omaha interfaces.
81 ScopedVariant app_;
82 ScopedVariant bundle_;
83 ScopedComPtr<IDispatch> update3_;
84
85 base::Timer polling_timer_;
86 };
87
88 // This class implements on-demand installation of the Chromoting Host by
89 // launching a per-user instance of Omaha and requesting elevation.
90 class DaemonCommandLineInstallerWin
91 : public DaemonInstallerWin,
92 public base::win::ObjectWatcher::Delegate {
93 public:
94 DaemonCommandLineInstallerWin(const CompletionCallback& done);
95 ~DaemonCommandLineInstallerWin();
96
97 // DaemonInstallerWin implementation.
98 virtual void Install() override;
99
100 // base::win::ObjectWatcher::Delegate implementation.
101 virtual void OnObjectSignaled(HANDLE object) override;
102
103 private:
104 // Handle of the launched process.
105 base::Process process_;
106
107 // Used to determine when the launched process terminates.
108 base::win::ObjectWatcher process_watcher_;
109 };
110
111 DaemonComInstallerWin::DaemonComInstallerWin(
112 const ScopedComPtr<IDispatch>& update3,
113 const CompletionCallback& done)
114 : DaemonInstallerWin(done),
115 update3_(update3),
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 HRESULT hr = dispatch::Invoke(update3_.get(), L"createAppBundleWeb",
127 DISPATCH_METHOD, bundle_.Receive());
128 if (FAILED(hr)) {
129 Done(hr);
130 return;
131 }
132 if (bundle_.type() != VT_DISPATCH) {
133 Done(DISP_E_TYPEMISMATCH);
134 return;
135 }
136
137 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"initialize", DISPATCH_METHOD,
138 nullptr);
139 if (FAILED(hr)) {
140 Done(hr);
141 return;
142 }
143
144 // Add Chromoting Host to the bundle.
145 ScopedVariant appid(kHostOmahaAppid);
146 ScopedVariant empty(kOmahaEmpty);
147 ScopedVariant language(kOmahaLanguage);
148 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"createApp", DISPATCH_METHOD,
149 appid, empty, language, empty, nullptr);
150 if (FAILED(hr)) {
151 Done(hr);
152 return;
153 }
154
155 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"checkForUpdate",
156 DISPATCH_METHOD, nullptr);
157 if (FAILED(hr)) {
158 Done(hr);
159 return;
160 }
161
162 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"appWeb",
163 DISPATCH_PROPERTYGET, ScopedVariant(0), app_.Receive());
164 if (FAILED(hr)) {
165 Done(hr);
166 return;
167 }
168 if (app_.type() != VT_DISPATCH) {
169 Done(DISP_E_TYPEMISMATCH);
170 return;
171 }
172
173 // Now poll for the installation status.
174 PollInstallationStatus();
175 }
176
177 void DaemonComInstallerWin::PollInstallationStatus() {
178 // Get the current application installation state.
179 // N.B. The object underlying the ICurrentState interface has static data that
180 // does not get updated as the server state changes. To get the most "current"
181 // state, the currentState property needs to be queried again.
182 ScopedVariant current_state;
183 HRESULT hr = dispatch::Invoke(V_DISPATCH(&app_), L"currentState",
184 DISPATCH_PROPERTYGET, current_state.Receive());
185 if (FAILED(hr)) {
186 Done(hr);
187 return;
188 }
189 if (current_state.type() != VT_DISPATCH) {
190 Done(DISP_E_TYPEMISMATCH);
191 return;
192 }
193
194 ScopedVariant state;
195 hr = dispatch::Invoke(V_DISPATCH(&current_state), L"stateValue",
196 DISPATCH_PROPERTYGET, state.Receive());
197 if (state.type() != VT_I4) {
198 Done(DISP_E_TYPEMISMATCH);
199 return;
200 }
201
202 // Perform state-specific actions.
203 switch (V_I4(&state)) {
204 case STATE_INIT:
205 case STATE_WAITING_TO_CHECK_FOR_UPDATE:
206 case STATE_CHECKING_FOR_UPDATE:
207 case STATE_WAITING_TO_DOWNLOAD:
208 case STATE_RETRYING_DOWNLOAD:
209 case STATE_DOWNLOADING:
210 case STATE_WAITING_TO_INSTALL:
211 case STATE_INSTALLING:
212 case STATE_PAUSED:
213 break;
214
215 case STATE_UPDATE_AVAILABLE:
216 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"download",
217 DISPATCH_METHOD, nullptr);
218 if (FAILED(hr)) {
219 Done(hr);
220 return;
221 }
222 break;
223
224 case STATE_DOWNLOAD_COMPLETE:
225 case STATE_EXTRACTING:
226 case STATE_APPLYING_DIFFERENTIAL_PATCH:
227 case STATE_READY_TO_INSTALL:
228 hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"install",
229 DISPATCH_METHOD, nullptr);
230 if (FAILED(hr)) {
231 Done(hr);
232 return;
233 }
234 break;
235
236 case STATE_INSTALL_COMPLETE:
237 case STATE_NO_UPDATE:
238 // Installation complete or not required. Report success.
239 Done(S_OK);
240 return;
241
242 case STATE_ERROR: {
243 ScopedVariant error_code;
244 hr = dispatch::Invoke(V_DISPATCH(&current_state), L"errorCode",
245 DISPATCH_PROPERTYGET, error_code.Receive());
246 if (FAILED(hr)) {
247 Done(hr);
248 return;
249 }
250 if (error_code.type() != VT_UI4) {
251 Done(DISP_E_TYPEMISMATCH);
252 return;
253 }
254 Done(V_UI4(&error_code));
255 return;
256 }
257
258 default:
259 LOG(ERROR) << "Unknown bundle state: " << V_I4(&state) << ".";
260 Done(E_FAIL);
261 return;
262 }
263
264 // Keep polling.
265 polling_timer_.Reset();
266 }
267
268 DaemonCommandLineInstallerWin::DaemonCommandLineInstallerWin(
269 const CompletionCallback& done) : DaemonInstallerWin(done) {
270 }
271
272 DaemonCommandLineInstallerWin::~DaemonCommandLineInstallerWin() {
273 process_watcher_.StopWatching();
274 }
275
276 void DaemonCommandLineInstallerWin::Install() {
277 // Get the full path to GoogleUpdate.exe from the registry.
278 base::win::RegKey update_key;
279 LONG result = update_key.Open(HKEY_CURRENT_USER,
280 kOmahaUpdateKeyName,
281 KEY_READ);
282 if (result != ERROR_SUCCESS) {
283 Done(HRESULT_FROM_WIN32(result));
284 return;
285 }
286
287 // presubmit: allow wstring
288 std::wstring google_update;
289 result = update_key.ReadValue(kOmahaPathValueName, &google_update);
290 if (result != ERROR_SUCCESS) {
291 Done(HRESULT_FROM_WIN32(result));
292 return;
293 }
294
295 // Launch the updater process and wait for its termination.
296 base::string16 command_line = base::WideToUTF16(
297 base::StringPrintf(kGoogleUpdateCommandLineFormat,
298 google_update.c_str(),
299 kHostOmahaAppid,
300 kOmahaLanguage));
301
302 base::LaunchOptions options;
303 process_ = base::LaunchProcess(command_line, options);
304 if (!process_.IsValid()) {
305 result = GetLastError();
306 Done(HRESULT_FROM_WIN32(result));
307 return;
308 }
309
310 if (!process_watcher_.StartWatching(process_.Handle(), this)) {
311 result = GetLastError();
312 Done(HRESULT_FROM_WIN32(result));
313 return;
314 }
315 }
316
317 void DaemonCommandLineInstallerWin::OnObjectSignaled(HANDLE object) {
318 // Check if the updater process returned success.
319 DWORD exit_code;
320 if (GetExitCodeProcess(process_.Handle(), &exit_code) && exit_code == 0) {
321 Done(S_OK);
322 } else {
323 Done(E_FAIL);
324 }
325 }
326
327 DaemonInstallerWin::DaemonInstallerWin(const CompletionCallback& done)
328 : done_(done) {
329 }
330
331 DaemonInstallerWin::~DaemonInstallerWin() {
332 }
333
334 void DaemonInstallerWin::Done(HRESULT result) {
335 CompletionCallback done = done_;
336 done_.Reset();
337 done.Run(result);
338 }
339
340 // static
341 scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create(
342 HWND window_handle,
343 CompletionCallback done) {
344 HRESULT result = E_FAIL;
345 ScopedComPtr<IDispatch> update3;
346
347 // Check if the machine instance of Omaha is available. The COM elevation is
348 // supported on Vista+, so on XP/W2K3 we assume that we are running under
349 // a privileged user and get ACCESS_DENIED later if we are not.
350 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
351 CLSID class_id;
352 result = CLSIDFromProgID(kGoogleUpdate, &class_id);
353 if (SUCCEEDED(result)) {
354 result = CoCreateInstance(class_id,
355 nullptr,
356 CLSCTX_LOCAL_SERVER,
357 IID_IDispatch,
358 update3.ReceiveVoid());
359 }
360 } else {
361 BIND_OPTS3 bind_options;
362 memset(&bind_options, 0, sizeof(bind_options));
363 bind_options.cbStruct = sizeof(bind_options);
364 bind_options.hwnd = GetTopLevelWindow(window_handle);
365 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER;
366 result = CoGetObject(kGoogleUpdateElevationMoniker,
367 &bind_options,
368 IID_IDispatch,
369 update3.ReceiveVoid());
370 }
371
372 if (result == CO_E_CLASSSTRING) {
373 // The machine instance of Omaha is not available so we will have to run
374 // GoogleUpdate.exe manually passing "needsadmin=True". This will cause
375 // Omaha to install the machine instance first and then install Chromoting
376 // Host.
377 return make_scoped_ptr(new DaemonCommandLineInstallerWin(done));
378 }
379
380 if (!SUCCEEDED(result)) {
381 // The user declined the UAC prompt or some other error occured.
382 done.Run(result);
383 return nullptr;
384 }
385
386 // The machine instance of Omaha is available and we successfully passed
387 // the UAC prompt.
388 return make_scoped_ptr(new DaemonComInstallerWin(update3, done));
389 }
390
391 HWND GetTopLevelWindow(HWND window) {
392 if (window == nullptr) {
393 return nullptr;
394 }
395
396 for (;;) {
397 LONG style = GetWindowLong(window, GWL_STYLE);
398 if ((style & WS_OVERLAPPEDWINDOW) == WS_OVERLAPPEDWINDOW ||
399 (style & WS_POPUP) == WS_POPUP) {
400 return window;
401 }
402
403 HWND parent = GetAncestor(window, GA_PARENT);
404 if (parent == nullptr) {
405 return window;
406 }
407
408 window = parent;
409 }
410 }
411
412 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698