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 "remoting/host/plugin/daemon_installer_win.h" | 5 #include "remoting/host/plugin/daemon_installer_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/process_util.h" | 11 #include "base/process_util.h" |
12 #include "base/string16.h" | 12 #include "base/string16.h" |
13 #include "base/stringize_macros.h" | 13 #include "base/stringize_macros.h" |
14 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
15 #include "base/time.h" | 15 #include "base/time.h" |
16 #include "base/timer.h" | 16 #include "base/timer.h" |
17 #include "base/win/object_watcher.h" | 17 #include "base/win/object_watcher.h" |
18 #include "base/win/registry.h" | 18 #include "base/win/registry.h" |
19 #include "base/win/scoped_bstr.h" | 19 #include "base/win/scoped_bstr.h" |
20 #include "base/win/scoped_comptr.h" | 20 #include "base/win/scoped_comptr.h" |
21 #include "base/win/scoped_handle.h" | 21 #include "base/win/scoped_handle.h" |
22 | |
23 namespace omaha { | |
24 #include "google_update/google_update_idl.h" | 22 #include "google_update/google_update_idl.h" |
25 } // namespace omaha | 23 #include "remoting/host/constants.h" |
26 | 24 |
27 using base::win::ScopedBstr; | 25 using base::win::ScopedBstr; |
28 using base::win::ScopedComPtr; | 26 using base::win::ScopedComPtr; |
29 | 27 |
30 namespace { | 28 namespace { |
31 | 29 |
32 // The COM elevation moniker for Omaha. | 30 // The COM elevation moniker for Omaha. |
33 const char16 kOmahaElevationMoniker[] = | 31 const char16 kOmahaElevationMoniker[] = |
34 TO_L_STRING("Elevation:Administrator!new:GoogleUpdate.Update3WebMachine"); | 32 TO_L_STRING("Elevation:Administrator!new:GoogleUpdate.Update3WebMachine"); |
35 | 33 |
36 // The registry key where the configuration of Omaha is stored. | 34 // The registry key where the configuration of Omaha is stored. |
37 const char16 kOmahaUpdateKeyName[] = TO_L_STRING("Software\\Google\\Update"); | 35 const char16 kOmahaUpdateKeyName[] = TO_L_STRING("Software\\Google\\Update"); |
38 | 36 |
39 // The name of the value where the full path to GoogleUpdate.exe is stored. | 37 // The name of the value where the full path to GoogleUpdate.exe is stored. |
40 const char16 kOmahaPathValueName[] = TO_L_STRING("path"); | 38 const char16 kOmahaPathValueName[] = TO_L_STRING("path"); |
41 | 39 |
42 // The command line format string for GoogleUpdate.exe | 40 // The command line format string for GoogleUpdate.exe |
43 const char16 kGoogleUpdateCommandLineFormat[] = | 41 const char16 kGoogleUpdateCommandLineFormat[] = |
44 TO_L_STRING("\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&") | 42 TO_L_STRING("\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&") |
45 TO_L_STRING("appname=Chromoting%%20Host&needsadmin=True&lang=%ls\""); | 43 TO_L_STRING("appname=Chromoting%%20Host&needsadmin=True&lang=%ls\""); |
46 | 44 |
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. | 45 // TODO(alexeypa): Get the desired laungage from the web app. |
52 const char16 kOmahaLanguage[] = TO_L_STRING("en"); | 46 const char16 kOmahaLanguage[] = TO_L_STRING("en"); |
53 | 47 |
54 // An empty string for optional parameters. | 48 // An empty string for optional parameters. |
55 const char16 kOmahaEmpty[] = TO_L_STRING(""); | 49 const char16 kOmahaEmpty[] = TO_L_STRING(""); |
56 | 50 |
57 // The installation status polling interval. | 51 // The installation status polling interval. |
58 const int kOmahaPollIntervalMs = 500; | 52 const int kOmahaPollIntervalMs = 500; |
59 | 53 |
60 } // namespace | 54 } // namespace |
61 | 55 |
62 namespace remoting { | 56 namespace remoting { |
63 | 57 |
64 // This class implements on-demand installation of the Chromoting Host via | 58 // This class implements on-demand installation of the Chromoting Host via |
65 // per-machine Omaha instance. | 59 // per-machine Omaha instance. |
66 class DaemonComInstallerWin : public DaemonInstallerWin { | 60 class DaemonComInstallerWin : public DaemonInstallerWin { |
67 public: | 61 public: |
68 DaemonComInstallerWin(const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3, | 62 DaemonComInstallerWin(const ScopedComPtr<IGoogleUpdate3Web>& update3, |
69 const CompletionCallback& done); | 63 const CompletionCallback& done); |
70 | 64 |
71 // DaemonInstallerWin implementation. | 65 // DaemonInstallerWin implementation. |
72 virtual void Install() OVERRIDE; | 66 virtual void Install() OVERRIDE; |
73 | 67 |
74 private: | 68 private: |
75 // Polls the installation status performing state-specific actions (such as | 69 // Polls the installation status performing state-specific actions (such as |
76 // starting installation once download has finished). | 70 // starting installation once download has finished). |
77 void PollInstallationStatus(); | 71 void PollInstallationStatus(); |
78 | 72 |
79 // Omaha interfaces. | 73 // Omaha interfaces. |
80 ScopedComPtr<omaha::IAppWeb> app_; | 74 ScopedComPtr<IAppWeb> app_; |
81 ScopedComPtr<omaha::IAppBundleWeb> bundle_; | 75 ScopedComPtr<IAppBundleWeb> bundle_; |
82 ScopedComPtr<omaha::IGoogleUpdate3Web> update3_; | 76 ScopedComPtr<IGoogleUpdate3Web> update3_; |
83 | 77 |
84 base::Timer polling_timer_; | 78 base::Timer polling_timer_; |
85 }; | 79 }; |
86 | 80 |
87 // This class implements on-demand installation of the Chromoting Host by | 81 // This class implements on-demand installation of the Chromoting Host by |
88 // launching a per-user instance of Omaha and requesting elevation. | 82 // launching a per-user instance of Omaha and requesting elevation. |
89 class DaemonCommandLineInstallerWin | 83 class DaemonCommandLineInstallerWin |
90 : public DaemonInstallerWin, | 84 : public DaemonInstallerWin, |
91 public base::win::ObjectWatcher::Delegate { | 85 public base::win::ObjectWatcher::Delegate { |
92 public: | 86 public: |
93 DaemonCommandLineInstallerWin(const CompletionCallback& done); | 87 DaemonCommandLineInstallerWin(const CompletionCallback& done); |
94 ~DaemonCommandLineInstallerWin(); | 88 ~DaemonCommandLineInstallerWin(); |
95 | 89 |
96 // DaemonInstallerWin implementation. | 90 // DaemonInstallerWin implementation. |
97 virtual void Install() OVERRIDE; | 91 virtual void Install() OVERRIDE; |
98 | 92 |
99 // base::win::ObjectWatcher::Delegate implementation. | 93 // base::win::ObjectWatcher::Delegate implementation. |
100 virtual void OnObjectSignaled(HANDLE object) OVERRIDE; | 94 virtual void OnObjectSignaled(HANDLE object) OVERRIDE; |
101 | 95 |
102 private: | 96 private: |
103 // Handle of the launched process. | 97 // Handle of the launched process. |
104 base::win::ScopedHandle process_; | 98 base::win::ScopedHandle process_; |
105 | 99 |
106 // Used to determine when the launched process terminates. | 100 // Used to determine when the launched process terminates. |
107 base::win::ObjectWatcher process_watcher_; | 101 base::win::ObjectWatcher process_watcher_; |
108 }; | 102 }; |
109 | 103 |
110 DaemonComInstallerWin::DaemonComInstallerWin( | 104 DaemonComInstallerWin::DaemonComInstallerWin( |
111 const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3, | 105 const ScopedComPtr<IGoogleUpdate3Web>& update3, |
112 const CompletionCallback& done) | 106 const CompletionCallback& done) |
113 : DaemonInstallerWin(done), | 107 : DaemonInstallerWin(done), |
114 update3_(update3), | 108 update3_(update3), |
115 ALLOW_THIS_IN_INITIALIZER_LIST( | 109 ALLOW_THIS_IN_INITIALIZER_LIST( |
116 polling_timer_( | 110 polling_timer_( |
117 FROM_HERE, | 111 FROM_HERE, |
118 base::TimeDelta::FromMilliseconds(kOmahaPollIntervalMs), | 112 base::TimeDelta::FromMilliseconds(kOmahaPollIntervalMs), |
119 base::Bind(&DaemonComInstallerWin::PollInstallationStatus, | 113 base::Bind(&DaemonComInstallerWin::PollInstallationStatus, |
120 base::Unretained(this)), | 114 base::Unretained(this)), |
121 false)) { | 115 false)) { |
122 } | 116 } |
123 | 117 |
124 void DaemonComInstallerWin::Install() { | 118 void DaemonComInstallerWin::Install() { |
125 // Create an app bundle. | 119 // Create an app bundle. |
126 ScopedComPtr<IDispatch> dispatch; | 120 ScopedComPtr<IDispatch> dispatch; |
127 HRESULT hr = update3_->createAppBundleWeb(dispatch.Receive()); | 121 HRESULT hr = update3_->createAppBundleWeb(dispatch.Receive()); |
128 if (FAILED(hr)) { | 122 if (FAILED(hr)) { |
129 Done(hr); | 123 Done(hr); |
130 return; | 124 return; |
131 } | 125 } |
132 | 126 |
133 hr = dispatch.QueryInterface(omaha::IID_IAppBundleWeb, bundle_.ReceiveVoid()); | 127 hr = dispatch.QueryInterface(IID_IAppBundleWeb, bundle_.ReceiveVoid()); |
134 if (FAILED(hr)) { | 128 if (FAILED(hr)) { |
135 Done(hr); | 129 Done(hr); |
136 return; | 130 return; |
137 } | 131 } |
138 | 132 |
139 hr = bundle_->initialize(); | 133 hr = bundle_->initialize(); |
140 if (FAILED(hr)) { | 134 if (FAILED(hr)) { |
141 Done(hr); | 135 Done(hr); |
142 return; | 136 return; |
143 } | 137 } |
144 | 138 |
145 // Add Chromoting Host to the bundle. | 139 // Add Chromoting Host to the bundle. |
146 ScopedBstr appid(kOmahaAppid); | 140 ScopedBstr appid(kHostOmahaAppid); |
147 ScopedBstr empty(kOmahaEmpty); | 141 ScopedBstr empty(kOmahaEmpty); |
148 ScopedBstr language(kOmahaLanguage); | 142 ScopedBstr language(kOmahaLanguage); |
149 hr = bundle_->createApp(appid, empty, language, empty); | 143 hr = bundle_->createApp(appid, empty, language, empty); |
150 if (FAILED(hr)) { | 144 if (FAILED(hr)) { |
151 Done(hr); | 145 Done(hr); |
152 return; | 146 return; |
153 } | 147 } |
154 | 148 |
155 hr = bundle_->checkForUpdate(); | 149 hr = bundle_->checkForUpdate(); |
156 if (FAILED(hr)) { | 150 if (FAILED(hr)) { |
157 Done(hr); | 151 Done(hr); |
158 return; | 152 return; |
159 } | 153 } |
160 | 154 |
161 dispatch.Release(); | 155 dispatch.Release(); |
162 hr = bundle_->get_appWeb(0, dispatch.Receive()); | 156 hr = bundle_->get_appWeb(0, dispatch.Receive()); |
163 if (FAILED(hr)) { | 157 if (FAILED(hr)) { |
164 Done(hr); | 158 Done(hr); |
165 return; | 159 return; |
166 } | 160 } |
167 | 161 |
168 hr = dispatch.QueryInterface(omaha::IID_IAppWeb, | 162 hr = dispatch.QueryInterface(IID_IAppWeb, |
169 app_.ReceiveVoid()); | 163 app_.ReceiveVoid()); |
170 if (FAILED(hr)) { | 164 if (FAILED(hr)) { |
171 Done(hr); | 165 Done(hr); |
172 return; | 166 return; |
173 } | 167 } |
174 | 168 |
175 // Now poll for the installation status. | 169 // Now poll for the installation status. |
176 PollInstallationStatus(); | 170 PollInstallationStatus(); |
177 } | 171 } |
178 | 172 |
179 void DaemonComInstallerWin::PollInstallationStatus() { | 173 void DaemonComInstallerWin::PollInstallationStatus() { |
180 // Get the current application installation state. | 174 // Get the current application installation state. |
181 // N.B. The object underlying the ICurrentState interface has static data that | 175 // 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" | 176 // does not get updated as the server state changes. To get the most "current" |
183 // state, the currentState property needs to be queried again. | 177 // state, the currentState property needs to be queried again. |
184 ScopedComPtr<IDispatch> dispatch; | 178 ScopedComPtr<IDispatch> dispatch; |
185 HRESULT hr = app_->get_currentState(dispatch.Receive()); | 179 HRESULT hr = app_->get_currentState(dispatch.Receive()); |
186 if (FAILED(hr)) { | 180 if (FAILED(hr)) { |
187 Done(hr); | 181 Done(hr); |
188 return; | 182 return; |
189 } | 183 } |
190 | 184 |
191 ScopedComPtr<omaha::ICurrentState> current_state; | 185 ScopedComPtr<ICurrentState> current_state; |
192 hr = dispatch.QueryInterface(omaha::IID_ICurrentState, | 186 hr = dispatch.QueryInterface(IID_ICurrentState, |
193 current_state.ReceiveVoid()); | 187 current_state.ReceiveVoid()); |
194 if (FAILED(hr)) { | 188 if (FAILED(hr)) { |
195 Done(hr); | 189 Done(hr); |
196 return; | 190 return; |
197 } | 191 } |
198 | 192 |
199 LONG state; | 193 LONG state; |
200 hr = current_state->get_stateValue(&state); | 194 hr = current_state->get_stateValue(&state); |
201 if (FAILED(hr)) { | 195 if (FAILED(hr)) { |
202 Done(hr); | 196 Done(hr); |
203 return; | 197 return; |
204 } | 198 } |
205 | 199 |
206 // Perform state-specific actions. | 200 // Perform state-specific actions. |
207 switch (state) { | 201 switch (state) { |
208 case omaha::STATE_INIT: | 202 case STATE_INIT: |
209 case omaha::STATE_WAITING_TO_CHECK_FOR_UPDATE: | 203 case STATE_WAITING_TO_CHECK_FOR_UPDATE: |
210 case omaha::STATE_CHECKING_FOR_UPDATE: | 204 case STATE_CHECKING_FOR_UPDATE: |
211 case omaha::STATE_WAITING_TO_DOWNLOAD: | 205 case STATE_WAITING_TO_DOWNLOAD: |
212 case omaha::STATE_RETRYING_DOWNLOAD: | 206 case STATE_RETRYING_DOWNLOAD: |
213 case omaha::STATE_DOWNLOADING: | 207 case STATE_DOWNLOADING: |
214 case omaha::STATE_WAITING_TO_INSTALL: | 208 case STATE_WAITING_TO_INSTALL: |
215 case omaha::STATE_INSTALLING: | 209 case STATE_INSTALLING: |
216 case omaha::STATE_PAUSED: | 210 case STATE_PAUSED: |
217 break; | 211 break; |
218 | 212 |
219 case omaha::STATE_UPDATE_AVAILABLE: | 213 case STATE_UPDATE_AVAILABLE: |
220 hr = bundle_->download(); | 214 hr = bundle_->download(); |
221 if (FAILED(hr)) { | 215 if (FAILED(hr)) { |
222 Done(hr); | 216 Done(hr); |
223 return; | 217 return; |
224 } | 218 } |
225 break; | 219 break; |
226 | 220 |
227 case omaha::STATE_DOWNLOAD_COMPLETE: | 221 case STATE_DOWNLOAD_COMPLETE: |
228 case omaha::STATE_EXTRACTING: | 222 case STATE_EXTRACTING: |
229 case omaha::STATE_APPLYING_DIFFERENTIAL_PATCH: | 223 case STATE_APPLYING_DIFFERENTIAL_PATCH: |
230 case omaha::STATE_READY_TO_INSTALL: | 224 case STATE_READY_TO_INSTALL: |
231 hr = bundle_->install(); | 225 hr = bundle_->install(); |
232 if (FAILED(hr)) { | 226 if (FAILED(hr)) { |
233 Done(hr); | 227 Done(hr); |
234 return; | 228 return; |
235 } | 229 } |
236 break; | 230 break; |
237 | 231 |
238 case omaha::STATE_INSTALL_COMPLETE: | 232 case STATE_INSTALL_COMPLETE: |
239 case omaha::STATE_NO_UPDATE: | 233 case STATE_NO_UPDATE: |
240 // Installation complete or not required. Report success. | 234 // Installation complete or not required. Report success. |
241 Done(S_OK); | 235 Done(S_OK); |
242 return; | 236 return; |
243 | 237 |
244 case omaha::STATE_ERROR: { | 238 case STATE_ERROR: { |
245 HRESULT error_code; | 239 HRESULT error_code; |
246 hr = current_state->get_errorCode(&error_code); | 240 hr = current_state->get_errorCode(&error_code); |
247 if (FAILED(hr)) { | 241 if (FAILED(hr)) { |
248 error_code = hr; | 242 error_code = hr; |
249 } | 243 } |
250 Done(error_code); | 244 Done(error_code); |
251 return; | 245 return; |
252 } | 246 } |
253 | 247 |
254 default: | 248 default: |
(...skipping 30 matching lines...) Expand all Loading... |
285 &google_update); | 279 &google_update); |
286 if (result != ERROR_SUCCESS) { | 280 if (result != ERROR_SUCCESS) { |
287 Done(HRESULT_FROM_WIN32(result)); | 281 Done(HRESULT_FROM_WIN32(result)); |
288 return; | 282 return; |
289 } | 283 } |
290 | 284 |
291 // Launch the updater process and wait for its termination. | 285 // Launch the updater process and wait for its termination. |
292 string16 command_line = | 286 string16 command_line = |
293 StringPrintf(kGoogleUpdateCommandLineFormat, | 287 StringPrintf(kGoogleUpdateCommandLineFormat, |
294 google_update.c_str(), | 288 google_update.c_str(), |
295 kOmahaAppid, | 289 kHostOmahaAppid, |
296 kOmahaLanguage); | 290 kOmahaLanguage); |
297 | 291 |
298 base::LaunchOptions options; | 292 base::LaunchOptions options; |
299 if (!base::LaunchProcess(command_line, options, process_.Receive())) { | 293 if (!base::LaunchProcess(command_line, options, process_.Receive())) { |
300 result = GetLastError(); | 294 result = GetLastError(); |
301 Done(HRESULT_FROM_WIN32(result)); | 295 Done(HRESULT_FROM_WIN32(result)); |
302 return; | 296 return; |
303 } | 297 } |
304 | 298 |
305 if (!process_watcher_.StartWatching(process_.Get(), this)) { | 299 if (!process_watcher_.StartWatching(process_.Get(), this)) { |
(...skipping 28 matching lines...) Expand all Loading... |
334 scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create( | 328 scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create( |
335 HWND window_handle, | 329 HWND window_handle, |
336 CompletionCallback done) { | 330 CompletionCallback done) { |
337 // Check if the machine instance of Omaha is available. | 331 // Check if the machine instance of Omaha is available. |
338 BIND_OPTS3 bind_options; | 332 BIND_OPTS3 bind_options; |
339 memset(&bind_options, 0, sizeof(bind_options)); | 333 memset(&bind_options, 0, sizeof(bind_options)); |
340 bind_options.cbStruct = sizeof(bind_options); | 334 bind_options.cbStruct = sizeof(bind_options); |
341 bind_options.hwnd = GetTopLevelWindow(window_handle); | 335 bind_options.hwnd = GetTopLevelWindow(window_handle); |
342 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; | 336 bind_options.dwClassContext = CLSCTX_LOCAL_SERVER; |
343 | 337 |
344 ScopedComPtr<omaha::IGoogleUpdate3Web> update3; | 338 ScopedComPtr<IGoogleUpdate3Web> update3; |
345 HRESULT result = ::CoGetObject( | 339 HRESULT result = ::CoGetObject( |
346 kOmahaElevationMoniker, | 340 kOmahaElevationMoniker, |
347 &bind_options, | 341 &bind_options, |
348 omaha::IID_IGoogleUpdate3Web, | 342 IID_IGoogleUpdate3Web, |
349 update3.ReceiveVoid()); | 343 update3.ReceiveVoid()); |
350 if (SUCCEEDED(result)) { | 344 if (SUCCEEDED(result)) { |
351 // The machine instance of Omaha is available and we successfully passed | 345 // The machine instance of Omaha is available and we successfully passed |
352 // the UAC prompt. | 346 // the UAC prompt. |
353 return scoped_ptr<DaemonInstallerWin>( | 347 return scoped_ptr<DaemonInstallerWin>( |
354 new DaemonComInstallerWin(update3, done)); | 348 new DaemonComInstallerWin(update3, done)); |
355 } else if (result == CO_E_CLASSSTRING) { | 349 } else if (result == CO_E_CLASSSTRING) { |
356 // The machine instance of Omaha is not available so we will have to run | 350 // The machine instance of Omaha is not available so we will have to run |
357 // GoogleUpdate.exe manually passing "needsadmin=True". This will cause | 351 // GoogleUpdate.exe manually passing "needsadmin=True". This will cause |
358 // Omaha to install the machine instance first and then install Chromoting | 352 // Omaha to install the machine instance first and then install Chromoting |
(...skipping 22 matching lines...) Expand all Loading... |
381 HWND parent = GetAncestor(window, GA_PARENT); | 375 HWND parent = GetAncestor(window, GA_PARENT); |
382 if (parent == NULL) { | 376 if (parent == NULL) { |
383 return window; | 377 return window; |
384 } | 378 } |
385 | 379 |
386 window = parent; | 380 window = parent; |
387 } | 381 } |
388 } | 382 } |
389 | 383 |
390 } // namespace remoting | 384 } // namespace remoting |
OLD | NEW |