Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(298)

Unified Diff: remoting/host/plugin/daemon_installer_win.cc

Issue 10021003: Implemented on-demand installation of the Chromoting Host on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: The last piece of CR feeback. Rebased. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/plugin/daemon_installer_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/plugin/daemon_installer_win.cc
diff --git a/remoting/host/plugin/daemon_installer_win.cc b/remoting/host/plugin/daemon_installer_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9d7e524f81f9362b25fdacac4f9b9e0b93563531
--- /dev/null
+++ b/remoting/host/plugin/daemon_installer_win.cc
@@ -0,0 +1,368 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "remoting/host/plugin/daemon_installer_win.h"
+
+#include <windows.h>
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "base/string16.h"
+#include "base/stringize_macros.h"
+#include "base/stringprintf.h"
+#include "base/time.h"
+#include "base/timer.h"
+#include "base/win/object_watcher.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_handle.h"
+
+namespace omaha {
+#include "google_update/google_update_idl.h"
+} // namespace omaha
+
+using base::win::ScopedBstr;
+using base::win::ScopedComPtr;
+
+namespace {
+
+// The COM elevation moniker for Omaha.
+const char16 kOmahaElevationMoniker[] =
+ TO_L_STRING("Elevation:Administrator!new:GoogleUpdate.Update3WebMachine");
+
+// The registry key where the configuration of Omaha is stored.
+const char16 kOmahaUpdateKeyName[] = TO_L_STRING("Software\\Google\\Update");
+
+// The name of the value where the full path to GoogleUpdate.exe is stored.
+const char16 kOmahaPathValueName[] = TO_L_STRING("path");
+
+// The command line format string for GoogleUpdate.exe
+const char16 kGoogleUpdateCommandLineFormat[] =
+ TO_L_STRING("\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&")
+ TO_L_STRING("appname=Chromoting%%20Host&needsadmin=True&lang=%ls\"");
+
+// The Omaha Appid of the host.
+const char16 kOmahaAppid[] =
+ TO_L_STRING("{b210701e-ffc4-49e3-932b-370728c72662}");
+
+// TODO(alexeypa): Get the desired laungage from the web app.
+const char16 kOmahaLanguage[] = TO_L_STRING("en");
+
+// An empty string for optional parameters.
+const char16 kOmahaEmpty[] = TO_L_STRING("");
+
+// The installation status polling interval.
+const int kOmahaPollIntervalMs = 500;
+
+} // namespace
+
+namespace remoting {
+
+// This class implements on-demand installation of the Chromoting Host via
+// per-machine Omaha instance.
+class DaemonComInstallerWin : public DaemonInstallerWin {
+ public:
+ DaemonComInstallerWin(const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3,
+ const CompletionCallback& done);
+
+ // DaemonInstallerWin implementation.
+ virtual void Install() OVERRIDE;
+
+ private:
+ // Polls the installation status performing state-specific actions (such as
+ // starting installation once download has finished).
+ void PollInstallationStatus();
+
+ // Omaha interfaces.
+ ScopedComPtr<omaha::IAppWeb> app_;
+ ScopedComPtr<omaha::IAppBundleWeb> bundle_;
+ ScopedComPtr<omaha::IGoogleUpdate3Web> update3_;
+
+ base::Timer polling_timer_;
+};
+
+// This class implements on-demand installation of the Chromoting Host by
+// launching a per-user instance of Omaha and requesting elevation.
+class DaemonCommandLineInstallerWin
+ : public DaemonInstallerWin,
+ public base::win::ObjectWatcher::Delegate {
+ public:
+ DaemonCommandLineInstallerWin(const CompletionCallback& done);
+ ~DaemonCommandLineInstallerWin();
+
+ // DaemonInstallerWin implementation.
+ virtual void Install() OVERRIDE;
+
+ // base::win::ObjectWatcher::Delegate implementation.
+ virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
+
+ private:
+ // Handle of the launched process.
+ base::win::ScopedHandle process_;
+
+ // Used to determine when the launched process terminates.
+ base::win::ObjectWatcher process_watcher_;
+};
+
+DaemonComInstallerWin::DaemonComInstallerWin(
+ const ScopedComPtr<omaha::IGoogleUpdate3Web>& update3,
+ const CompletionCallback& done)
+ : DaemonInstallerWin(done),
+ update3_(update3),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ polling_timer_(
+ FROM_HERE,
+ base::TimeDelta::FromMilliseconds(kOmahaPollIntervalMs),
+ base::Bind(&DaemonComInstallerWin::PollInstallationStatus,
+ base::Unretained(this)),
+ false)) {
+}
+
+void DaemonComInstallerWin::Install() {
+ // Create an app bundle.
+ ScopedComPtr<IDispatch> dispatch;
+ HRESULT hr = update3_->createAppBundleWeb(dispatch.Receive());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ hr = dispatch.QueryInterface(omaha::IID_IAppBundleWeb, bundle_.ReceiveVoid());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ hr = bundle_->initialize();
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ // Add Chromoting Host to the bundle.
+ ScopedBstr appid(kOmahaAppid);
+ ScopedBstr empty(kOmahaEmpty);
+ ScopedBstr language(kOmahaLanguage);
+ hr = bundle_->createApp(appid, empty, language, empty);
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ hr = bundle_->checkForUpdate();
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ dispatch.Release();
+ hr = bundle_->get_appWeb(0, dispatch.Receive());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ hr = dispatch.QueryInterface(omaha::IID_IAppWeb,
+ app_.ReceiveVoid());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ // Now poll for the installation status.
+ PollInstallationStatus();
+}
+
+void DaemonComInstallerWin::PollInstallationStatus() {
+ // Get the current application installation state.
+ // N.B. The object underlying the ICurrentState interface has static data that
+ // does not get updated as the server state changes. To get the most "current"
+ // state, the currentState property needs to be queried again.
+ ScopedComPtr<IDispatch> dispatch;
+ HRESULT hr = app_->get_currentState(dispatch.Receive());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ ScopedComPtr<omaha::ICurrentState> current_state;
+ hr = dispatch.QueryInterface(omaha::IID_ICurrentState,
+ current_state.ReceiveVoid());
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ LONG state;
+ hr = current_state->get_stateValue(&state);
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+
+ // Perform state-specific actions.
+ switch (state) {
+ case omaha::STATE_INIT:
+ case omaha::STATE_WAITING_TO_CHECK_FOR_UPDATE:
+ case omaha::STATE_CHECKING_FOR_UPDATE:
+ case omaha::STATE_WAITING_TO_DOWNLOAD:
+ case omaha::STATE_RETRYING_DOWNLOAD:
+ case omaha::STATE_DOWNLOADING:
+ case omaha::STATE_WAITING_TO_INSTALL:
+ case omaha::STATE_INSTALLING:
+ case omaha::STATE_PAUSED:
+ break;
+
+ case omaha::STATE_UPDATE_AVAILABLE:
+ hr = bundle_->download();
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+ break;
+
+ case omaha::STATE_DOWNLOAD_COMPLETE:
+ case omaha::STATE_EXTRACTING:
+ case omaha::STATE_APPLYING_DIFFERENTIAL_PATCH:
+ case omaha::STATE_READY_TO_INSTALL:
+ hr = bundle_->install();
+ if (FAILED(hr)) {
+ Done(hr);
+ return;
+ }
+ break;
+
+ case omaha::STATE_INSTALL_COMPLETE:
+ case omaha::STATE_NO_UPDATE:
+ // Installation complete or not required. Report success.
+ Done(S_OK);
+ return;
+
+ case omaha::STATE_ERROR: {
+ HRESULT error_code;
+ hr = current_state->get_errorCode(&error_code);
+ if (FAILED(hr)) {
+ error_code = hr;
+ }
+ Done(error_code);
+ return;
+ }
+
+ default:
+ LOG(ERROR) << "Unknown bundle state: " << state << ".";
+ Done(E_FAIL);
+ return;
+ }
+
+ // Keep polling.
+ polling_timer_.Reset();
+}
+
+DaemonCommandLineInstallerWin::DaemonCommandLineInstallerWin(
+ const CompletionCallback& done) : DaemonInstallerWin(done) {
+}
+
+DaemonCommandLineInstallerWin::~DaemonCommandLineInstallerWin() {
+ process_watcher_.StopWatching();
+}
+
+void DaemonCommandLineInstallerWin::Install() {
+ // Get the full path to GoogleUpdate.exe from the registry.
+ base::win::RegKey update_key;
+ LONG result = update_key.Open(HKEY_CURRENT_USER,
+ kOmahaUpdateKeyName,
+ KEY_READ);
+ if (result != ERROR_SUCCESS) {
+ Done(HRESULT_FROM_WIN32(result));
+ return;
+ }
+
+ string16 google_update;
+ result = update_key.ReadValue(kOmahaPathValueName,
+ &google_update);
+ if (result != ERROR_SUCCESS) {
+ Done(HRESULT_FROM_WIN32(result));
+ return;
+ }
+
+ // Launch the updater process and wait for its termination.
+ string16 command_line =
+ StringPrintf(kGoogleUpdateCommandLineFormat,
+ google_update.c_str(),
+ kOmahaAppid,
+ kOmahaLanguage);
+
+ base::LaunchOptions options;
+ if (!base::LaunchProcess(command_line, options, process_.Receive())) {
+ result = GetLastError();
+ Done(HRESULT_FROM_WIN32(result));
+ return;
+ }
+
+ if (!process_watcher_.StartWatching(process_.Get(), this)) {
+ result = GetLastError();
+ Done(HRESULT_FROM_WIN32(result));
+ return;
+ }
+}
+
+void DaemonCommandLineInstallerWin::OnObjectSignaled(HANDLE object) {
+ // Check if the updater process returned success.
+ DWORD exit_code;
+ if (GetExitCodeProcess(process_.Get(), &exit_code) && exit_code == 0) {
+ Done(S_OK);
+ } else {
+ Done(E_FAIL);
+ }
+}
+
+DaemonInstallerWin::DaemonInstallerWin(const CompletionCallback& done)
+ : done_(done) {
+}
+
+DaemonInstallerWin::~DaemonInstallerWin() {
+}
+
+void DaemonInstallerWin::Done(HRESULT result) {
+ done_.Run(result);
+}
+
+// static
+scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create(
+ CompletionCallback done) {
+ // Check if the machine instance of Omaha is available.
+ BIND_OPTS3 bind_options;
+ memset(&bind_options, 0, sizeof(bind_options));
+ bind_options.cbStruct = sizeof(bind_options);
+ bind_options.hwnd = NULL;
+ bind_options.dwClassContext = CLSCTX_LOCAL_SERVER;
+
+ ScopedComPtr<omaha::IGoogleUpdate3Web> update3;
+ HRESULT result = ::CoGetObject(
+ kOmahaElevationMoniker,
+ &bind_options,
+ omaha::IID_IGoogleUpdate3Web,
+ update3.ReceiveVoid());
+ if (SUCCEEDED(result)) {
+ // The machine instance of Omaha is available and we successfully passed
+ // the UAC prompt.
+ return scoped_ptr<DaemonInstallerWin>(
+ new DaemonComInstallerWin(update3, done));
+ } else if (result == CO_E_CLASSSTRING) {
+ // The machine instance of Omaha is not available so we will have to run
+ // GoogleUpdate.exe manually passing "needsadmin=True". This will cause
+ // Omaha to install the machine instance first and then install Chromoting
+ // Host.
+ return scoped_ptr<DaemonInstallerWin>(
+ new DaemonCommandLineInstallerWin(done));
+ } else {
+ // The user declined the UAC prompt or some other error occured.
+ done.Run(result);
+ return scoped_ptr<DaemonInstallerWin>();
+ }
+}
+
+} // namespace remoting
« no previous file with comments | « remoting/host/plugin/daemon_installer_win.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698