OLD | NEW |
---|---|
(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 "chrome/browser/extensions/app_host/binaries_installer_internal.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/win/scoped_bstr.h" | |
9 #include "base/win/scoped_comptr.h" | |
10 #include "google_update/google_update_idl.h" | |
11 | |
12 using base::win::ScopedBstr; | |
13 using base::win::ScopedComPtr; | |
14 | |
15 namespace app_host { | |
16 namespace internal { | |
17 | |
18 namespace { | |
19 | |
20 const wchar_t kBinariesAppId[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; | |
21 const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"; | |
22 | |
23 HRESULT CheckIsBusy(IAppBundle* app_bundle, bool* is_busy) { | |
24 VARIANT_BOOL variant_is_busy = VARIANT_TRUE; | |
25 HRESULT hr = app_bundle->isBusy(&variant_is_busy); | |
26 if (FAILED(hr)) { | |
27 LOG(ERROR) << "Failed to check app_bundle->isBusy: " << hr; | |
miket_OOO
2012/08/23 23:51:01
No braces needed for these one-line blocks.
erikwright (departed)
2012/08/31 21:04:48
Done.
| |
28 } else { | |
29 *is_busy = (variant_is_busy == VARIANT_TRUE); | |
30 } | |
31 return hr; | |
32 } | |
33 | |
34 HRESULT OnUpdateAvailable(IAppBundle* app_bundle) { | |
35 // If the app bundle is 'busy' we will just wait some more. | |
miket_OOO
2012/08/23 23:51:01
Why quotes around busy? Does it mean something dif
erikwright (departed)
2012/08/31 21:04:48
Done.
| |
36 bool is_busy = false; | |
37 HRESULT hr = CheckIsBusy(app_bundle, &is_busy); | |
robertshield
2012/08/16 21:15:53
what does it mean for the app bundle to be 'busy'
| |
38 if (SUCCEEDED(hr) && !is_busy) { | |
39 hr = app_bundle->download(); | |
40 if (FAILED(hr)) | |
41 LOG(ERROR) << "Failed to initiate bundle download: " << hr; | |
42 } | |
43 return hr; | |
44 } | |
45 | |
46 HRESULT OnReadyToInstall(IAppBundle* app_bundle) { | |
47 // If the app bundle is 'busy' we will just wait some more. | |
48 bool is_busy = false; | |
49 HRESULT hr = CheckIsBusy(app_bundle, &is_busy); | |
50 if (SUCCEEDED(hr) && !is_busy) { | |
51 hr = app_bundle->install(); | |
52 if (FAILED(hr)) | |
53 LOG(ERROR) << "Failed to initiate bundle install: " << hr; | |
54 } | |
55 return hr; | |
56 } | |
57 | |
58 HRESULT OnError(ICurrentState* current_state) { | |
59 LONG error_code; | |
60 HRESULT hr = current_state->get_errorCode(&error_code); | |
61 if (FAILED(hr)) { | |
62 LOG(ERROR) << "Failed to retrieve bundle error code: " << hr; | |
63 } else { | |
64 hr = error_code; | |
65 | |
66 ScopedBstr completion_message; | |
67 HRESULT completion_message_hr = | |
68 current_state->get_completionMessage(completion_message.Receive()); | |
69 if (FAILED(completion_message_hr)) { | |
70 LOG(ERROR) << "Bundle installation failed with error " << hr | |
71 << ". Error message retrieval failed with error: " | |
72 << completion_message_hr; | |
miket_OOO
2012/08/23 23:51:01
one-liner braces
erikwright (departed)
2012/08/31 21:04:48
I don't think these qualify as one-liner according
| |
73 } else { | |
74 LOG(ERROR) << "Bundle installation failed with error " << hr << ": " | |
75 << completion_message; | |
76 } | |
77 } | |
78 | |
79 return hr; | |
80 } | |
81 | |
82 HRESULT GetCurrentState(IApp* app, | |
83 ICurrentState** current_state, | |
84 CurrentState* state_value) { | |
85 HRESULT hr = S_OK; | |
86 | |
87 ScopedComPtr<ICurrentState> temp_current_state; | |
88 { | |
89 ScopedComPtr<IDispatch> idispatch; | |
90 hr = app->get_currentState(idispatch.Receive()); | |
91 if (FAILED(hr)) { | |
92 LOG(ERROR) << "Failed to get App Bundle state: " << hr; | |
93 } else { | |
94 hr = temp_current_state.QueryFrom(idispatch); | |
95 if (FAILED(hr)) | |
96 LOG(ERROR) << "Unexpected error: " << hr; | |
miket_OOO
2012/08/23 23:51:01
Might as well give a little more context for this
erikwright (departed)
2012/08/31 21:04:48
Done.
| |
97 } | |
98 } | |
99 | |
100 if (SUCCEEDED(hr)) { | |
101 LONG long_state_value; | |
102 hr = temp_current_state->get_stateValue(&long_state_value); | |
103 if (FAILED(hr)) | |
104 LOG(ERROR) << "Failed to get App Bundle state value: " << hr; | |
105 *state_value = static_cast<CurrentState>(long_state_value); | |
106 *current_state = temp_current_state.Detach(); | |
107 } | |
108 | |
109 return hr; | |
110 } | |
111 | |
112 HRESULT CreateInstalledApp(IAppBundle* app_bundle, | |
113 const wchar_t* app_guid, | |
114 IApp** app) { | |
115 ScopedComPtr<IApp> temp_app; | |
116 ScopedComPtr<IDispatch> idispatch; | |
117 HRESULT hr = app_bundle->createInstalledApp(ScopedBstr(app_guid), | |
118 idispatch.Receive()); | |
119 if (FAILED(hr)) { | |
120 LOG(ERROR) << "Failed to configure App Bundle: " << hr; | |
121 } else { | |
122 hr = temp_app.QueryFrom(idispatch); | |
123 if (FAILED(hr)) | |
124 LOG(ERROR) << "Unexpected error: " << hr; | |
125 else | |
126 *app = temp_app.Detach(); | |
127 } | |
128 | |
129 return hr; | |
130 } | |
131 | |
132 } // namespace | |
133 | |
134 bool CheckIfDone(IAppBundle* app_bundle, IApp* app, HRESULT* hr) { | |
miket_OOO
2012/08/23 23:51:01
Suggestion: if you have a local hr that's copied t
erikwright (departed)
2012/08/31 21:04:48
No, hr is returned to the caller of InstallBinarie
miket_OOO
2012/08/31 21:48:43
OK, good. I should have looked but I'd convinced m
| |
135 ScopedComPtr<ICurrentState> current_state; | |
136 CurrentState state_value; | |
137 *hr = GetCurrentState(app, current_state.Receive(), &state_value); | |
138 | |
139 bool complete = false; | |
140 | |
141 if (SUCCEEDED(hr)) { | |
142 switch (state_value) { | |
143 case STATE_WAITING_TO_CHECK_FOR_UPDATE: | |
144 case STATE_CHECKING_FOR_UPDATE: | |
145 case STATE_WAITING_TO_DOWNLOAD: | |
146 case STATE_RETRYING_DOWNLOAD: | |
147 case STATE_DOWNLOADING: | |
148 case STATE_WAITING_TO_INSTALL: | |
149 case STATE_INSTALLING: | |
150 case STATE_DOWNLOAD_COMPLETE: | |
151 case STATE_EXTRACTING: | |
152 case STATE_APPLYING_DIFFERENTIAL_PATCH: | |
153 // These states will all transition on their own. | |
154 break; | |
155 | |
156 case STATE_UPDATE_AVAILABLE: | |
157 *hr = OnUpdateAvailable(app_bundle); | |
158 break; | |
159 | |
160 case STATE_READY_TO_INSTALL: | |
161 *hr = OnReadyToInstall(app_bundle); | |
162 break; | |
163 | |
164 case STATE_NO_UPDATE: | |
165 LOG(INFO) << "Google Update reports that the binaries are already " | |
166 << "installed and up-to-date."; | |
167 complete = true; | |
168 break; | |
169 | |
170 case STATE_INSTALL_COMPLETE: | |
171 complete = true; | |
172 break; | |
173 | |
174 case STATE_ERROR: | |
175 *hr = OnError(current_state); | |
176 break; | |
177 | |
178 case STATE_INIT: | |
179 case STATE_PAUSED: | |
180 default: | |
181 LOG(ERROR) << "Unexpected bundle state: " << state_value << "."; | |
182 *hr = E_FAIL; | |
183 break; | |
184 } | |
185 } | |
186 | |
187 return FAILED(*hr) || complete; | |
188 } | |
189 | |
190 HRESULT CreateAppBundle(IGoogleUpdate3* update3, IAppBundle** app_bundle) { | |
191 HRESULT hr = S_OK; | |
192 | |
193 ScopedComPtr<IAppBundle> temp_app_bundle; | |
194 { | |
195 ScopedComPtr<IDispatch> idispatch; | |
196 hr = update3->createAppBundle(idispatch.Receive()); | |
197 if (FAILED(hr)) { | |
198 LOG(ERROR) << "Failed to createAppBundle: " << hr; | |
199 } else { | |
200 hr = temp_app_bundle.QueryFrom(idispatch); | |
201 if (FAILED(hr)) | |
202 LOG(ERROR) << "Unexpected error: " << hr; | |
203 } | |
204 } | |
205 | |
206 if (SUCCEEDED(hr)) { | |
207 hr = temp_app_bundle->initialize(); | |
208 if (FAILED(hr)) | |
209 LOG(ERROR) << "Failed to initialize App Bundle: " << hr; | |
210 else | |
211 *app_bundle = temp_app_bundle.Detach(); | |
212 } | |
213 | |
214 return hr; | |
215 } | |
216 | |
217 HRESULT GetAppHostAPValue(IGoogleUpdate3* update3, BSTR* ap_value) { | |
218 ScopedComPtr<IAppBundle> app_bundle; | |
219 HRESULT hr = CreateAppBundle(update3, app_bundle.Receive()); | |
220 if (SUCCEEDED(hr)) { | |
221 ScopedComPtr<IApp> app; | |
222 hr = CreateInstalledApp(app_bundle, kAppHostAppId, app.Receive()); | |
223 if (SUCCEEDED(hr)) { | |
224 hr = app->get_ap(ap_value); | |
225 if (FAILED(hr)) | |
226 LOG(ERROR) << "Failed to get the App Host AP value."; | |
227 } | |
228 } | |
229 | |
230 return hr; | |
231 } | |
232 | |
233 HRESULT CreateBinariesIApp(IAppBundle* app_bundle, BSTR ap, IApp** app) { | |
234 HRESULT hr = S_OK; | |
235 | |
236 ScopedComPtr<IApp> temp_app; | |
237 { | |
238 ScopedComPtr<IDispatch> idispatch; | |
239 hr = app_bundle->createApp(ScopedBstr(kBinariesAppId), idispatch.Receive()); | |
240 if (FAILED(hr)) { | |
241 LOG(ERROR) << "Failed to configure App Bundle: " << hr; | |
242 } else { | |
243 hr = temp_app.QueryFrom(idispatch); | |
244 if (FAILED(hr)) | |
245 LOG(ERROR) << "Unexpected error: " << hr; | |
246 } | |
247 } | |
248 | |
249 if (SUCCEEDED(hr)) { | |
250 hr = temp_app->put_isEulaAccepted(VARIANT_TRUE); | |
251 if (FAILED(hr)) | |
252 LOG(ERROR) << "Failed to set 'EULA Accepted': " << hr; | |
253 } | |
254 | |
255 if (SUCCEEDED(hr)) { | |
256 hr = temp_app->put_ap(ap); | |
257 if (FAILED(hr)) | |
258 LOG(ERROR) << "Failed to set AP value: " << hr; | |
259 } | |
260 | |
261 if (SUCCEEDED(hr)) | |
262 *app = temp_app.Detach(); | |
miket_OOO
2012/08/23 23:51:01
This could slide, but I can see cases where temp_a
erikwright (departed)
2012/08/31 21:04:48
Are you suggesting that a potential code change co
miket_OOO
2012/08/31 21:48:43
Ah, OK. I was confused. It belongs to the RAII guy
| |
263 | |
264 return S_OK; | |
265 } | |
266 | |
267 HRESULT CreateGoogleUpdate3(IGoogleUpdate3** update3) { | |
268 ScopedComPtr<IGoogleUpdate3> temp_update3; | |
269 HRESULT hr = temp_update3.CreateInstance(CLSID_GoogleUpdate3UserClass); | |
270 if (FAILED(hr)) { | |
miket_OOO
2012/08/23 23:51:01
It's slightly easier to read if the SUCCEEDED() ca
erikwright (departed)
2012/08/31 21:04:48
Done.
| |
271 // TODO(erikwright): Try in-proc to support running elevated? According | |
272 // to update3_utils.cc (CreateGoogleUpdate3UserClass): | |
273 // The primary reason for the LocalServer activation failing on Vista/Win7 | |
274 // is that COM does not look at HKCU registration when the code is running | |
275 // elevated. We fall back to an in-proc mode. The in-proc mode is limited to | |
276 // one install at a time, so we use it only as a backup mechanism. | |
277 LOG(ERROR) << "Failed to instantiate GoogleUpdate3: " << hr; | |
278 } else { | |
279 *update3 = temp_update3.Detach(); | |
280 } | |
281 return hr; | |
282 } | |
283 | |
284 HRESULT SelectBinariesApValue(IGoogleUpdate3* update3, BSTR* ap_value) { | |
285 HRESULT hr = GetAppHostAPValue(update3, ap_value); | |
286 if (FAILED(hr)) { | |
287 // TODO(erikwright): distinguish between AppHost not installed and an | |
288 // error in GetAppHostAPValue. | |
289 // TODO(erikwright): Use stable by default when App Host support is in | |
290 // stable. | |
291 ScopedBstr temp_ap_value; | |
292 if (NULL == temp_ap_value.Allocate(L"2.0-dev-multi-apphost")) { | |
293 LOG(ERROR) << "Unexpected error in ScopedBstr::Allocate."; | |
294 hr = E_FAIL; | |
295 } else { | |
296 *ap_value = temp_ap_value.Release(); | |
297 hr = S_OK; | |
298 } | |
299 } | |
300 | |
301 return hr; | |
302 } | |
303 | |
304 } // namespace internal | |
305 } // namespace app_host | |
OLD | NEW |