Chromium Code Reviews| 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 |