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 const wchar_t kBinariesAppId[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}"; | |
20 const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"; | |
21 } // namespace | |
22 | |
23 bool CheckIfDone(IAppBundle* app_bundle, IApp* app, HRESULT* hr) { | |
24 *hr = S_OK; | |
25 ScopedComPtr<ICurrentState> current_state; | |
26 { | |
27 ScopedComPtr<IDispatch> idispatch; | |
28 *hr = app->get_currentState(idispatch.Receive()); | |
29 if (FAILED(*hr)) { | |
30 LOG(ERROR) << "Failed to get App Bundle state: " << *hr; | |
31 return true; | |
32 } | |
33 *hr = current_state.QueryFrom(idispatch); | |
34 if (FAILED(*hr)) { | |
35 LOG(ERROR) << "get_currentState return object is not an ICurrentState."; | |
36 return true; | |
37 } | |
38 } | |
39 | |
40 LONG long_state_value; | |
41 CurrentState state_value; | |
42 *hr = current_state->get_stateValue(&long_state_value); | |
43 if (FAILED(*hr)) { | |
44 LOG(ERROR) << "Failed to get App Bundle state value: " << *hr; | |
45 return true; | |
46 } | |
47 state_value = static_cast<CurrentState>(long_state_value); | |
48 switch (state_value) { | |
49 case STATE_WAITING_TO_CHECK_FOR_UPDATE: | |
50 case STATE_CHECKING_FOR_UPDATE: | |
51 case STATE_WAITING_TO_DOWNLOAD: | |
52 case STATE_RETRYING_DOWNLOAD: | |
53 case STATE_DOWNLOADING: | |
54 case STATE_WAITING_TO_INSTALL: | |
55 case STATE_INSTALLING: | |
56 case STATE_DOWNLOAD_COMPLETE: | |
57 case STATE_EXTRACTING: | |
58 case STATE_APPLYING_DIFFERENTIAL_PATCH: | |
59 // These states will all transition on their own. | |
60 break; | |
61 | |
62 case STATE_UPDATE_AVAILABLE: | |
63 // If the app bundle is 'busy' we will just wait some more. | |
64 { | |
65 VARIANT_BOOL is_busy = VARIANT_TRUE; | |
66 *hr = app_bundle->isBusy(&is_busy); | |
67 if (FAILED(*hr)) { | |
68 LOG(ERROR) << "Failed to check app_bundle->isBusy: " << *hr; | |
69 return true; | |
70 } | |
71 | |
72 if (!is_busy) { | |
73 *hr = app_bundle->download(); | |
74 if (FAILED(*hr)) { | |
75 LOG(ERROR) << "Failed to initiate bundle download: " << *hr; | |
76 return true; | |
77 } | |
78 } | |
79 } | |
80 break; | |
81 | |
82 case STATE_READY_TO_INSTALL: | |
83 // If the app bundle is 'busy' we will just wait some more. | |
84 { | |
85 VARIANT_BOOL is_busy = VARIANT_TRUE; | |
86 *hr = app_bundle->isBusy(&is_busy); | |
87 if (FAILED(*hr)) { | |
88 LOG(ERROR) << "Failed to check app_bundle->isBusy: " << *hr; | |
89 return true; | |
robertshield
2012/08/16 13:08:16
as a readability thing, could we reduce the number
erikwright (departed)
2012/08/16 21:05:15
Done.
| |
90 } | |
91 | |
92 if (!is_busy) { | |
93 *hr = app_bundle->install(); | |
94 if (FAILED(*hr)) { | |
95 LOG(ERROR) << "Failed to initiate bundle install: " << *hr; | |
96 return true; | |
97 } | |
98 } | |
99 } | |
100 break; | |
101 | |
102 case STATE_NO_UPDATE: | |
103 LOG(INFO) << "Google Update reports that the binaries are already " | |
104 << "installed and up-to-date."; | |
105 *hr = S_OK; | |
106 return true; | |
107 | |
108 case STATE_INSTALL_COMPLETE: | |
109 return S_OK; | |
110 *hr = S_OK; | |
robertshield
2012/08/16 13:08:16
this should be warning about unreachable code
erikwright (departed)
2012/08/16 21:05:15
Done.
| |
111 return true; | |
112 | |
113 case STATE_ERROR: { | |
114 LONG error_code; | |
115 *hr = current_state->get_errorCode(&error_code); | |
116 if (FAILED(*hr)) { | |
117 LOG(ERROR) << "Failed to retrieve bundle error code: " << *hr; | |
118 return true; | |
119 } | |
120 *hr = error_code; | |
121 ScopedBstr completion_message; | |
122 HRESULT completion_message_hr = | |
123 current_state->get_completionMessage(completion_message.Receive()); | |
124 if (FAILED(completion_message_hr)) { | |
125 LOG(ERROR) << "Bundle installation failed with error " << *hr | |
126 << ". Error message retrieval failed with error: " | |
127 << completion_message_hr; | |
128 } else { | |
129 LOG(ERROR) << "Bundle installation failed with error " << *hr << ": " | |
130 << completion_message; | |
131 } | |
132 return true; | |
133 } | |
134 | |
135 case STATE_INIT: | |
136 case STATE_PAUSED: | |
137 LOG(ERROR) << "Unexpected bundle state: " << state_value << "."; | |
138 *hr = E_FAIL; | |
139 return true; | |
140 | |
141 default: | |
142 LOG(ERROR) << "Unknown bundle state: " << state_value << "."; | |
143 *hr = E_FAIL; | |
144 return true; | |
145 } | |
146 | |
147 DCHECK_EQ(*hr, S_OK); | |
148 return false; | |
149 } | |
150 | |
151 HRESULT CreateAppBundle(IGoogleUpdate3* update3, IAppBundle** app_bundle) { | |
152 HRESULT hr = S_OK; | |
153 ScopedComPtr<IAppBundle> temp_app_bundle; | |
154 { | |
155 ScopedComPtr<IDispatch> idispatch; | |
156 hr = update3->createAppBundle(idispatch.Receive()); | |
157 if (FAILED(hr)) { | |
158 LOG(ERROR) << "Failed to createAppBundle: " << hr; | |
159 return hr; | |
160 } | |
161 | |
162 hr = temp_app_bundle.QueryFrom(idispatch); | |
163 if (FAILED(hr)) { | |
164 LOG(ERROR) << "Unexpected error: " << hr; | |
165 return hr; | |
166 } | |
167 } | |
168 | |
169 hr = temp_app_bundle->initialize(); | |
170 if (FAILED(hr)) { | |
171 LOG(ERROR) << "Failed to initialize App Bundle: " << hr; | |
172 return hr; | |
173 } | |
174 | |
175 *app_bundle = temp_app_bundle.Detach(); | |
176 | |
177 return S_OK; | |
178 } | |
179 | |
180 HRESULT GetAppHostAPValue(IGoogleUpdate3* update3, BSTR* ap_value) { | |
181 ScopedComPtr<IAppBundle> app_bundle; | |
182 HRESULT hr = CreateAppBundle(update3, app_bundle.Receive()); | |
183 if (FAILED(hr)) { | |
184 return hr; | |
185 } | |
186 | |
187 ScopedComPtr<IApp> app; | |
188 { | |
189 ScopedComPtr<IDispatch> idispatch; | |
190 hr = app_bundle->createInstalledApp(ScopedBstr(kAppHostAppId), | |
191 idispatch.Receive()); | |
192 if (FAILED(hr)) { | |
193 LOG(ERROR) << "Failed to configure App Bundle: " << hr; | |
194 return hr; | |
robertshield
2012/08/16 13:08:16
I would encourage you to rewrite stuff like this w
erikwright (departed)
2012/08/16 21:05:15
Done.
| |
195 } | |
196 hr = app.QueryFrom(idispatch); | |
197 if (FAILED(hr)) { | |
198 LOG(ERROR) << "Unexpected error: " << hr; | |
199 return hr; | |
200 } | |
201 } | |
202 hr = app->get_ap(ap_value); | |
203 if (FAILED(hr)) { | |
204 LOG(ERROR) << "Failed to get the App Host AP value."; | |
205 return hr; | |
206 } | |
207 return S_OK; | |
208 } | |
209 | |
210 HRESULT CreateBinariesIApp(IAppBundle* app_bundle, BSTR ap, IApp** app) { | |
robertshield
2012/08/16 13:08:16
app, ap, and app_bundle :) maybe ap -> "channel_va
erikwright (departed)
2012/08/16 21:05:15
What does AP stand for?
robertshield
2012/08/16 21:15:53
That knowledge is lost in the sands of time. Omaha
| |
211 HRESULT hr(S_OK); | |
212 ScopedComPtr<IApp> temp_app; | |
213 { | |
214 ScopedComPtr<IDispatch> idispatch; | |
215 hr = app_bundle->createApp(ScopedBstr(kBinariesAppId), idispatch.Receive()); | |
216 if (FAILED(hr)) { | |
217 LOG(ERROR) << "Failed to configure App Bundle: " << hr; | |
218 return hr; | |
219 } | |
220 hr = temp_app.QueryFrom(idispatch); | |
221 if (FAILED(hr)) { | |
222 LOG(ERROR) << "Unexpected error: " << hr; | |
223 return hr; | |
224 } | |
225 } | |
226 hr = temp_app->put_isEulaAccepted(VARIANT_TRUE); | |
227 if (FAILED(hr)) { | |
228 LOG(ERROR) << "Failed to set 'EULA Accepted': " << hr; | |
229 return hr; | |
230 } | |
231 hr = temp_app->put_ap(ap); | |
232 if (FAILED(hr)) { | |
233 LOG(ERROR) << "Failed to set AP value: " << hr; | |
234 return hr; | |
235 } | |
236 *app = temp_app.Detach(); | |
237 return S_OK; | |
238 } | |
239 | |
240 HRESULT CreateGoogleUpdate3(IGoogleUpdate3** update3) { | |
241 ScopedComPtr<IGoogleUpdate3> temp_update3; | |
242 HRESULT hr = temp_update3.CreateInstance(CLSID_GoogleUpdate3UserClass); | |
243 if (FAILED(hr)) { | |
244 // TODO(erikwright): Try in-proc to support running elevated? According | |
245 // to update3_utils.cc (CreateGoogleUpdate3UserClass): | |
246 // The primary reason for the LocalServer activation failing on Vista/Win7 | |
247 // is that COM does not look at HKCU registration when the code is running | |
248 // elevated. We fall back to an in-proc mode. The in-proc mode is limited to | |
249 // one install at a time, so we use it only as a backup mechanism. | |
250 LOG(ERROR) << "Failed to instantiate GoogleUpdate3: " << hr; | |
251 } else { | |
252 *update3 = temp_update3.Detach(); | |
253 } | |
254 return hr; | |
255 } | |
256 | |
257 HRESULT SelectBinariesApValue(IGoogleUpdate3* update3, BSTR* ap_value) { | |
258 HRESULT hr = GetAppHostAPValue(update3, ap_value); | |
259 if (FAILED(hr)) { | |
260 // TODO(erikwright): distinguish between AppHost not installed and an | |
261 // error in GetAppHostAPValue. | |
262 // TODO(erikwright): Use stable by default when App Host support is in | |
263 // stable. | |
264 ScopedBstr temp_ap_value; | |
265 if (NULL == temp_ap_value.Allocate(L"2.0-dev-multi-apphost")) { | |
266 LOG(ERROR) << "Unexpected error in ScopedBstr::Allocate."; | |
267 hr = E_FAIL; | |
268 } else { | |
269 *ap_value = temp_ap_value.Release(); | |
270 hr = S_OK; | |
271 } | |
272 } | |
273 | |
274 return hr; | |
275 } | |
276 | |
277 } // namespace internal | |
278 } // namespace app_host | |
OLD | NEW |