12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "apps/app_host/binaries_installer.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/platform_thread.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_bstr.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_com_initializer.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/scoped_comptr.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_update/google_update_idl.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace app_host {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Helpers --------------------------------------------------------------------
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kAppHostAppId[] = L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const wchar_t kBinariesAppId[] = L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}";
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kInstallationPollingIntervalMs = 50;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT CreateInstalledApp(IAppBundle* app_bundle,
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           const wchar_t* app_guid,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                           IApp** app) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IDispatch> idispatch;
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = app_bundle->createInstalledApp(base::win::ScopedBstr(app_guid),
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                              idispatch.Receive());
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to configure App Bundle: " << hr;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IApp> temp_app;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app.QueryFrom(idispatch);
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected error querying IApp from "
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "IAppBundle->createInstalledApp return value: " << hr;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *app = temp_app.Detach();
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT GetAppHostApValue(IGoogleUpdate3* update3,
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          IAppBundle* app_bundle,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          BSTR* ap_value) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IApp> app;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = CreateInstalledApp(app_bundle, kAppHostAppId, app.Receive());
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = app->get_ap(ap_value);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to get the App Launcher AP value.";
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT GetCurrentState(IApp* app,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        ICurrentState** current_state,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        CurrentState* state_value) {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IDispatch> idispatch;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = app->get_currentState(idispatch.Receive());
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to get App Bundle state: " << hr;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<ICurrentState> temp_current_state;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_current_state.QueryFrom(idispatch);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected error querying ICurrentState from "
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "IApp::get_currentState return value: " << hr;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG long_state_value;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_current_state->get_stateValue(&long_state_value);
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (SUCCEEDED(hr)) {
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *state_value = static_cast<CurrentState>(long_state_value);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *current_state = temp_current_state.Detach();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to get App Bundle state value: " << hr;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool CheckIsBusy(IAppBundle* app_bundle, HRESULT* hr) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  VARIANT_BOOL variant_is_busy = VARIANT_TRUE;
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *hr = app_bundle->isBusy(&variant_is_busy);
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(*hr))
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to check app_bundle->isBusy: " << *hr;
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return (variant_is_busy == VARIANT_TRUE);
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OnUpdateAvailable(IAppBundle* app_bundle, HRESULT* hr) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the app bundle is busy we will just wait some more.
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CheckIsBusy(app_bundle, hr) || FAILED(*hr))
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *hr = app_bundle->download();
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(*hr))
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to initiate bundle download: " << *hr;
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OnReadyToInstall(IAppBundle* app_bundle, HRESULT* hr) {
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the app bundle is busy we will just wait some more.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (CheckIsBusy(app_bundle, hr) || FAILED(*hr))
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *hr = app_bundle->install();
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(*hr))
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to initiate bundle install: " << *hr;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT OnError(ICurrentState* current_state) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG error_code;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = current_state->get_errorCode(&error_code);
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to retrieve bundle error code: " << hr;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedBstr completion_message;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT completion_message_hr =
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    current_state->get_completionMessage(completion_message.Receive());
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(completion_message_hr)) {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Bundle installation failed with error " << error_code
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << ". Error message retrieval failed with error: "
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << completion_message_hr;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Bundle installation failed with error " << error_code << ": "
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << completion_message;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return error_code;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT CreateGoogleUpdate3(IGoogleUpdate3** update3) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IGoogleUpdate3> temp_update3;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = temp_update3.CreateInstance(CLSID_GoogleUpdate3UserClass);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (SUCCEEDED(hr)) {
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *update3 = temp_update3.Detach();
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // TODO(erikwright): Try in-proc to support running elevated? According
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to update3_utils.cc (CreateGoogleUpdate3UserClass):
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // The primary reason for the LocalServer activation failing on Vista/Win7
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // is that COM does not look at HKCU registration when the code is running
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // elevated. We fall back to an in-proc mode. The in-proc mode is limited to
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one install at a time, so we use it only as a backup mechanism.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to instantiate GoogleUpdate3: " << hr;
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT CreateAppBundle(IGoogleUpdate3* update3, IAppBundle** app_bundle) {
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IDispatch> idispatch;
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = update3->createAppBundle(idispatch.Receive());
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to createAppBundle: " << hr;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IAppBundle> temp_app_bundle;
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app_bundle.QueryFrom(idispatch);
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected error querying IAppBundle from "
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "IGoogleUpdate3->createAppBundle return value: " << hr;
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app_bundle->initialize();
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to initialize App Bundle: " << hr;
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *app_bundle = temp_app_bundle.Detach();
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT SelectBinariesApValue(IGoogleUpdate3* update3,
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              BSTR* ap_value) {
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(erikwright): Uncomment this when we correctly propagate the AP value
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // from the system-level binaries when quick-enabling the app host at
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // user-level (http://crbug.com/178479).
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // base::win::ScopedComPtr<IAppBundle> app_bundle;
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // HRESULT hr = CreateAppBundle(update3, app_bundle.Receive());
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if (FAILED(hr))
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   return hr;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // hr = GetAppHostApValue(update3, app_bundle, ap_value);
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // if (SUCCEEDED(hr))
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  //   return hr;
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(erikwright): distinguish between AppHost not installed and an
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // error in GetAppHostApValue.
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // TODO(erikwright): Use stable by default when App Host support is in
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // stable.
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedBstr temp_ap_value;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (temp_ap_value.Allocate(L"2.0-dev-multi-apphost") == NULL) {
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected error in ScopedBstr::Allocate.";
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_FAIL;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *ap_value = temp_ap_value.Release();
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return S_OK;
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT CreateBinariesIApp(IAppBundle* app_bundle, BSTR ap, IApp** app) {
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IDispatch> idispatch;
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = app_bundle->createApp(base::win::ScopedBstr(kBinariesAppId),
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     idispatch.Receive());
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to configure App Bundle: " << hr;
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IApp> temp_app;
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app.QueryFrom(idispatch);
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Unexpected error querying IApp from "
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << "IAppBundle->createApp return value: " << hr;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app->put_isEulaAccepted(VARIANT_TRUE);
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to set 'EULA Accepted': " << hr;
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = temp_app->put_ap(ap);
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to set AP value: " << hr;
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *app = temp_app.Detach();
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool CheckIfDone(IAppBundle* app_bundle, IApp* app, HRESULT* hr) {
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<ICurrentState> current_state;
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  CurrentState state_value;
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *hr = GetCurrentState(app, current_state.Receive(), &state_value);
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(*hr))
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (state_value) {
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_WAITING_TO_CHECK_FOR_UPDATE:
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_CHECKING_FOR_UPDATE:
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_WAITING_TO_DOWNLOAD:
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_RETRYING_DOWNLOAD:
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_DOWNLOADING:
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_WAITING_TO_INSTALL:
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_INSTALLING:
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_DOWNLOAD_COMPLETE:
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_EXTRACTING:
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_APPLYING_DIFFERENTIAL_PATCH:
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // These states will all transition on their own.
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_UPDATE_AVAILABLE:
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      OnUpdateAvailable(app_bundle, hr);
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return FAILED(*hr);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_READY_TO_INSTALL:
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      OnReadyToInstall(app_bundle, hr);
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return FAILED(*hr);
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_NO_UPDATE:
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(INFO) << "Google Update reports that the binaries are already "
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                << "installed and up-to-date.";
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_INSTALL_COMPLETE:
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_ERROR:
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *hr = OnError(current_state);
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return FAILED(*hr);
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_INIT:
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case STATE_PAUSED:
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    default:
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      LOG(ERROR) << "Unexpected bundle state: " << state_value << ".";
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *hr = E_FAIL;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Globals --------------------------------------------------------------------
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)HRESULT InstallBinaries() {
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedCOMInitializer initialize_com;
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!initialize_com.succeeded()) {
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "COM initialization failed";
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return E_FAIL;
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IGoogleUpdate3> update3;
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRESULT hr = CreateGoogleUpdate3(update3.Receive());
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedBstr ap_value;
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = SelectBinariesApValue(update3, ap_value.Receive());
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IAppBundle> app_bundle;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = CreateAppBundle(update3, app_bundle.Receive());
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::win::ScopedComPtr<IApp> app;
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = CreateBinariesIApp(app_bundle, ap_value, app.Receive());
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr))
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  hr = app_bundle->checkForUpdate();
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (FAILED(hr)) {
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LOG(ERROR) << "Failed to initiate update check: " << hr;
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return hr;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We rely upon Omaha to eventually time out and transition to a failure
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // state.
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (!CheckIfDone(app_bundle, app, &hr)) {
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        kInstallationPollingIntervalMs));
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return hr;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace app_host
335