summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/google/google_update.cc2
-rw-r--r--google_update/README.chromium25
-rw-r--r--google_update/google_update_idl.idl783
-rw-r--r--remoting/host/plugin/DEPS3
-rw-r--r--remoting/host/plugin/daemon_controller_win.cc118
-rw-r--r--remoting/host/plugin/daemon_installer_win.cc368
-rw-r--r--remoting/host/plugin/daemon_installer_win.h47
-rw-r--r--remoting/remoting.gyp3
8 files changed, 1294 insertions, 55 deletions
diff --git a/chrome/browser/google/google_update.cc b/chrome/browser/google/google_update.cc
index 8457f1a..b3d39fa 100644
--- a/chrome/browser/google/google_update.cc
+++ b/chrome/browser/google/google_update.cc
@@ -156,7 +156,7 @@ class GoogleUpdateJobObserver
STDMETHOD(OnPause)() {
return S_OK;
}
- STDMETHOD(OnComplete)(CompletionCodes code, const TCHAR* text) {
+ STDMETHOD(OnComplete)(LegacyCompletionCodes code, const TCHAR* text) {
switch (code) {
case COMPLETION_CODE_SUCCESS_CLOSE_UI:
case COMPLETION_CODE_SUCCESS: {
diff --git a/google_update/README.chromium b/google_update/README.chromium
index b6676f6..248ad70 100644
--- a/google_update/README.chromium
+++ b/google_update/README.chromium
@@ -1,2 +1,23 @@
-This IDL was provided by the Google Update team so that we could use the new
-On-Demand checking for updates.
+Originally this IDL was provided by the Google Update team so that we could use
+the On-Demand checking for updates. Now it is copied from the public Omaha
+repository with minor modifications. See
+http://omaha.googlecode.com/svn/trunk/official/goopdate/omaha3_idl.idl.
+
+This copy is based on http://omaha.googlecode.com/svn/trunk/official/goopdate/omaha3_idl.idl@120
+with the following two coclasses removed:
+
+ [
+ uuid(___AUTO_GENERATED_GUID___),
+ helpstring("GoogleComProxyMachineClass")
+ ]
+ coclass GoogleComProxyMachineClass {
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(___AUTO_GENERATED_GUID___),
+ helpstring("GoogleComProxyUserClass")
+ ]
+ coclass GoogleComProxyUserClass {
+ [default] interface IUnknown;
+ }
diff --git a/google_update/google_update_idl.idl b/google_update/google_update_idl.idl
index a8889b8..bcaadfe 100644
--- a/google_update/google_update_idl.idl
+++ b/google_update/google_update_idl.idl
@@ -1,13 +1,593 @@
-// Copyright 2006 Google Inc. All Rights Reserved.
+// Copyright 2009-2010 Google Inc.
//
-// Author: Vivek Rao - vivekrao@google.com
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
//
-// The proxy clsid #defined as PROXY_CLSID_IS in mk_common needs to be changed
-// anytime any interface below changes, or if a new interface is added.
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================================================================
import "oaidl.idl";
import "ocidl.idl";
+// When adding interfaces to this file:
+// * Do not use "Google" or "GoogleUpdate" directly. Instead, use preprocessor
+// defines.
+// * Add a test for the Google-specific value to
+// omaha_customization_goopdate_apis_unittest.cc.
+
+//
+// Enums.
+// These values can be passed to interface methods and/or compared to their
+// output.
+//
+
+// Must be kept in sync with the enum in base/browser_utils.h.
+typedef enum BrowserType {
+ BROWSER_UNKNOWN = 0,
+ BROWSER_DEFAULT = 1,
+ BROWSER_INTERNET_EXPLORER = 2,
+ BROWSER_FIREFOX = 3,
+ BROWSER_CHROME = 4,
+} BrowserType;
+
+// The normal install flow proceeds from STATE_INIT through
+// STATE_INSTALL_COMPLETE in order, skipping states that are not relevant.
+// All exceptions and terminal states are start with STATE_INSTALL_COMPLETE.
+typedef enum CurrentState {
+ STATE_INIT = 1,
+ STATE_WAITING_TO_CHECK_FOR_UPDATE = 2,
+ STATE_CHECKING_FOR_UPDATE = 3,
+ STATE_UPDATE_AVAILABLE = 4,
+ STATE_WAITING_TO_DOWNLOAD = 5,
+ STATE_RETRYING_DOWNLOAD = 6,
+ STATE_DOWNLOADING = 7,
+ STATE_DOWNLOAD_COMPLETE = 8,
+ STATE_EXTRACTING = 9,
+ STATE_APPLYING_DIFFERENTIAL_PATCH = 10,
+ // TODO(omaha3): Should we move STATE_DOWNLOAD_COMPLETE here and eliminate
+ // STATE_READY_TO_INSTALL?
+ STATE_READY_TO_INSTALL = 11,
+ STATE_WAITING_TO_INSTALL = 12,
+ STATE_INSTALLING = 13,
+ STATE_INSTALL_COMPLETE = 14,
+ STATE_PAUSED = 15,
+ STATE_NO_UPDATE = 16,
+ STATE_ERROR = 17,
+} CurrentState;
+
+typedef enum InstallPriority {
+ INSTALL_PRIORITY_LOW = 0,
+ INSTALL_PRIORITY_HIGH = 10,
+} InstallPriority;
+
+// Specifies what the client should do after installation.
+typedef enum PostInstallAction {
+ POST_INSTALL_ACTION_DEFAULT = 0,
+
+ // Caller should exit silently.
+ POST_INSTALL_ACTION_EXIT_SILENTLY = 1,
+
+ // Caller should launch the command.
+ POST_INSTALL_ACTION_LAUNCH_COMMAND = 2,
+
+ // Caller should launch the command and exit silently.
+ POST_INSTALL_ACTION_EXIT_SILENTLY_ON_LAUNCH_COMMAND = 3,
+
+ // The caller should ask the user to restart the browser. If the value of
+ // IApp's browser is supported and postInstallUrl is valid, the client should
+ // offer to restart the browser. If the user chooses to do so, the client
+ // should launch the ICurrentState::postInstallUrl after shutting down and
+ // restarting the browser.
+ POST_INSTALL_ACTION_RESTART_BROWSER = 4,
+
+ // Similar to POST_INSTALL_ACTION_RESTART_BROWSER, but ask the user to shut
+ // down all browsers.
+ POST_INSTALL_ACTION_RESTART_ALL_BROWSERS = 5,
+
+ // The caller should ask the user to reboot the machine.
+ POST_INSTALL_ACTION_REBOOT = 6,
+} PostInstallAction;
+
+[
+ object,
+ dual,
+ uuid(6DB17455-4E85-46e7-9D23-E555E4B005AF),
+ helpstring("IGoogleUpdate3 Interface"),
+ pointer_default(unique)
+]
+interface IGoogleUpdate3 : IDispatch {
+ // TODO(Omaha): Perhaps this interface exposes helpers such as
+ // RestartBrowsers, etc.
+
+ // Returns the count of the AppBundles in this IGoogleUpdate3 interface.
+ [id(1), propget] HRESULT Count([out, retval] long* count);
+
+ // Returns an IDispatch of the AppBundle in this IGoogleUpdate3 interface at
+ // the specified 0-based index. This property has the dispid of DISPID_VALUE
+ // to make it the default property of IGoogleUpdate3.
+ [id(DISPID_VALUE), propget] HRESULT Item([in] long index,
+ [out, retval] IDispatch** bundle);
+ // Returns an IDispatch to a newly created empty AppBundle.
+ [id(2)] HRESULT createAppBundle([out, retval] IDispatch** app_bundle);
+}
+
+[
+ object,
+ dual,
+ uuid(313cfb25-4888-4fc6-9e19-764d8c5fc8f8),
+ helpstring("IAppBundle Interface"),
+ pointer_default(unique)
+]
+interface IAppBundle : IDispatch {
+ // TODO(omaha3): AppBundle::display_name_ is never used. Should we remove?
+ [propget] HRESULT displayName([out, retval] BSTR*);
+ [propput] HRESULT displayName([in] BSTR);
+
+ [propget] HRESULT displayLanguage([out, retval] BSTR*);
+ [propput] HRESULT displayLanguage([in] BSTR);
+
+ [propget] HRESULT installSource([out, retval] BSTR*);
+ [propput] HRESULT installSource([in] BSTR);
+
+ [propget] HRESULT originURL([out, retval] BSTR*);
+ [propput] HRESULT originURL([in] BSTR);
+
+ [propget] HRESULT offlineDirectory([out, retval] BSTR* offline_dir);
+ [propput] HRESULT offlineDirectory([in] BSTR offline_dir);
+
+ [propget] HRESULT sessionId([out, retval] BSTR* session_id);
+ [propput] HRESULT sessionId([in] BSTR session_id);
+
+ // The priority property determines download speed/priority and the number/
+ // frequency of retries. Use values from the InstallPriority enum.
+ [propget] HRESULT priority([out, retval] long* priority);
+ [propput] HRESULT priority([in] long priority);
+
+ // Returns the count of the Apps in the AppBundle.
+ [id(1), propget] HRESULT Count([out, retval] long* count);
+
+ // Returns an IDispatch of the App in the AppBundle at the specified 0-based
+ // index. This property has the dispid of DISPID_VALUE to make it the default
+ // property of IAppBundle.
+ [id(DISPID_VALUE), propget] HRESULT Item([in] long index,
+ [out, retval] IDispatch** app);
+
+ // Impersonation and primary tokens set by the client. Typically only
+ // set by the gupdatem service. The gupdatem service exposes a narrow
+ // interface to medium integrity clients. When a medium integrity client calls
+ // into the gupdatem service, the gupdatem service captures the token of the
+ // caller, and then calls put_altTokens() on the gupdate service, so that the
+ // gupdate service can use it for future download() and install() requests.
+ [propput] HRESULT altTokens([in] ULONG_PTR impersonation_token,
+ [in] ULONG_PTR primary_token,
+ [in] DWORD caller_proc_id);
+
+ // Sets a HWND to associate with the client, if any. This will be used as
+ // the parent window for any dialogs that the server may need to display.
+ [propput] HRESULT parentHWND([in] ULONG_PTR hwnd);
+
+ // Initializes the bundle with the properties that have been set.
+ [id(2)] HRESULT initialize();
+
+ // Returns an IDispatch to a new App for the specified app id.
+ // The App is added to the Bundle.
+ [id(3)] HRESULT createApp([in] BSTR app_id,
+ [out, retval] IDispatch** app);
+
+ // Returns an IDispatch to a newly created App for the specified app ID. The
+ // App is populated with information from the existing installation and added
+ // to the Bundle. Fails if the specified app is not installed.
+ [id(4)] HRESULT createInstalledApp([in] BSTR app_id,
+ [out, retval] IDispatch** app);
+
+ // Creates App instances for all installed apps managed by this Omaha
+ // instance. Each App is populated with information from the existing install.
+ [id(5)] HRESULT createAllInstalledApps();
+
+ // These methods are non-blocking. The operation is scheduled.
+ [id(6)] HRESULT checkForUpdate();
+ [id(7)] HRESULT download();
+ [id(8)] HRESULT install();
+
+ // All-in-one function for automatically updating all apps. Populates the
+ // bundle then schedules the update, which includes the update check and
+ // download and install, if necessary.
+ [id(9)] HRESULT updateAllApps();
+
+ // These three methods are non-blocking. The operation is requested.
+ [id(10)] HRESULT stop();
+ [id(11)] HRESULT pause();
+ [id(12)] HRESULT resume();
+
+ // Returns true if the bundle has an uncompleted non-blocking request.
+ [id(13)] HRESULT isBusy([out, retval] VARIANT_BOOL* is_busy);
+
+ // Downloads a package of an installed application.
+ [id(14)] HRESULT downloadPackage([in] BSTR app_id, [in] BSTR package_name);
+
+ // TODO(omaha): Define this aggregated bundle state. Is this really a property
+ // or should it be getCurrentState?
+ // The server and bundle are the only thing that can provide aggregated
+ // time estimates for downloads. Also, aggregate percentage is not currently
+ // available to the client because the total bytes to download is not
+ // available from App in all post-update check states.
+ // To do this, we will probably need to know the total expected download
+ // size for all packages to be installed - those that are required or in use -
+ // by the time the update check phase is complete.
+ [id(15), propget] HRESULT currentState([out, retval] VARIANT* current_state);
+};
+
+[
+ object,
+ dual,
+ uuid(D999CE21-98B3-4894-BACB-A49A1D50848F),
+ helpstring("IApp Interface"),
+ pointer_default(unique)
+]
+interface IApp : IDispatch {
+ // Returns a version IDispatch object.
+ [id(1), propget] HRESULT currentVersion([out, retval] IDispatch** current);
+ [id(2), propget] HRESULT nextVersion([out, retval] IDispatch** next);
+
+ [propget] HRESULT appId([out, retval] BSTR*);
+
+ [propget] HRESULT displayName([out, retval] BSTR*);
+ [propput] HRESULT displayName([in] BSTR);
+
+ [propget] HRESULT language([out, retval] BSTR*);
+ [propput] HRESULT language([in] BSTR);
+
+ [propget] HRESULT ap([out, retval] BSTR*);
+ [propput] HRESULT ap([in] BSTR);
+
+ [propget] HRESULT ttToken([out, retval] BSTR*);
+ [propput] HRESULT ttToken([in] BSTR);
+
+ [propget] HRESULT iid([out, retval] BSTR*);
+ [propput] HRESULT iid([in] BSTR);
+
+ [propget] HRESULT brandCode([out, retval] BSTR*);
+ [propput] HRESULT brandCode([in] BSTR);
+
+ [propget] HRESULT clientId([out, retval] BSTR*);
+ [propput] HRESULT clientId([in] BSTR);
+
+ [propget] HRESULT labels([out, retval] BSTR*);
+ [propput] HRESULT labels([in] BSTR);
+
+ [propget] HRESULT referralId([out, retval] BSTR*);
+ [propput] HRESULT referralId([in] BSTR);
+
+ // Use values from the BrowserType enum.
+ [propget] HRESULT browserType([out, retval] UINT*);
+ [propput] HRESULT browserType([in] UINT);
+
+ [propget] HRESULT clientInstallData([out, retval] BSTR*);
+ [propput] HRESULT clientInstallData([in] BSTR);
+
+ [propget] HRESULT serverInstallDataIndex([out, retval] BSTR*);
+ [propput] HRESULT serverInstallDataIndex([in] BSTR);
+
+ // Set as soon as possible. Error pings are disabled until set to true.
+ [propget] HRESULT isEulaAccepted([out, retval] VARIANT_BOOL*);
+ [propput] HRESULT isEulaAccepted([in] VARIANT_BOOL);
+
+ [propget] HRESULT usageStatsEnable([out, retval] UINT*);
+ [propput] HRESULT usageStatsEnable([in] UINT);
+
+ [propget] HRESULT installTimeDiffSec([out, retval] UINT*);
+
+ // Returns an ICurrentState interface. The object underlying the 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.
+ [propget] HRESULT currentState([out, retval] IDispatch**);
+};
+
+[
+ object,
+ dual,
+ uuid(BCDCB538-01C0-46d1-A6A7-52F4D021C272),
+ helpstring("IAppVersion Interface"),
+ pointer_default(unique)
+]
+interface IAppVersion : IDispatch {
+ [propget] HRESULT version([out, retval] BSTR*);
+
+ // [propget] HRESULT installManifest([out, retval] BSTR*);
+
+ // Returns the count of the Packages in the AppVersion.
+ [propget] HRESULT packageCount([out, retval] long* count);
+
+ // Returns an IDispatch of the Package in the AppVersion at the specified
+ // 0-based index.
+ [propget] HRESULT package([in] long index,
+ [out, retval] IDispatch** package);
+};
+
+[
+ object,
+ dual,
+ uuid(DCAB8386-4F03-4dbd-A366-D90BC9F68DE6),
+ helpstring("IPackage Interface"),
+ pointer_default(unique)
+]
+interface IPackage : IDispatch {
+ // Retrieves the package from the package cache and copies it to the
+ // directory provided. Returns an error is the package is not available
+ // locally.
+ [id(1)] HRESULT get([in] BSTR dir);
+
+ // Returns true if the package has been downloaded and is available
+ // locally.
+ [propget] HRESULT isAvailable([out, retval] VARIANT_BOOL*);
+
+ // Returns the manifest name of the package.
+ [propget] HRESULT filename([out, retval] BSTR*);
+};
+
+// TODO(omaha3): We should figure out what else we are going to want in this
+// interface before dogfood even if we do not implement it.
+[
+ object,
+ dual,
+ uuid(247954F9-9EDC-4E68-8CC3-150C2B89EADF),
+ helpstring("ICurrentState Interface"),
+ pointer_default(unique)
+]
+interface ICurrentState : IDispatch {
+ // This interface is exposed to web clients!
+ // TODO(omaha3): Update valid comments once we settle on an implementation.
+
+ // A value from the CurrentState enum. This value determines which of the
+ // properties below are valid.
+ [propget] HRESULT stateValue([out, retval] LONG*);
+
+ // The remaining properties are only valid in the specified states. For all
+ // other states, the values are not specified.
+
+ // This property is valid only when stateValue is STATE_UPDATE_AVAILABLE.
+ [propget] HRESULT availableVersion([out, retval] BSTR*);
+
+ // The following three properties are only valid when stateValue is
+ // STATE_WAITING_TO_DOWNLOAD, STATE_RETRYING_DOWNLOAD, STATE_DOWNLOADING,
+ // STATE_DOWNLOAD_COMPLETE, STATE_EXTRACTING,
+ // STATE_APPLYING_DIFFERENTIAL_PATCH, or STATE_READY_TO_INSTALL.
+
+ // Bytes downloaded so far.
+ [propget] HRESULT bytesDownloaded([out, retval] ULONG*);
+
+ // Total bytes to download.
+ [propget] HRESULT totalBytesToDownload([out, retval] ULONG*);
+
+ // Estimated download time remaining in ms. -1 indicates unknown.
+ // Progress may not always be available, so clients should handle the -1 case.
+ [propget] HRESULT downloadTimeRemainingMs([out, retval] LONG*);
+
+ [propget] HRESULT nextRetryTime([out, retval] ULONGLONG*);
+
+ // TODO(omaha 3): Need some way to indicate reconnecting, retrying, etc.
+
+ // The following two properties are only valid when stateValue is
+ // STATE_INSTALLING or STATE_INSTALL_COMPLETE.
+
+ // Current install progress in percentage from 0 to 100. -1 indicates unknown.
+ // Progress may not always be available, so clients should handle the -1 case.
+ [propget] HRESULT installProgress([out, retval] LONG*);
+
+ // Estimated download time remaining in ms. -1 indicates unknown.
+ // Progress may not always be available, so clients should handle the -1 case.
+ [propget] HRESULT installTimeRemainingMs([out, retval] LONG*);
+
+ // The following four properties are only valid when stateValue is
+ // STATE_ERROR:
+
+ // Returns true if the app has been canceled.
+ [propget] HRESULT isCanceled([out, retval] VARIANT_BOOL* is_canceled);
+
+ // Error code.
+ [propget] HRESULT errorCode([out, retval] LONG*);
+
+ // Error extra code.
+ [propget] HRESULT extraCode1([out, retval] LONG*);
+
+ // The following three properties are only valid when stateValue is
+ // STATE_ERROR or STATE_INSTALL_COMPLETE.
+ // TODO(omaha3): If STATE_DOWNLOAD_COMPLETE or STATE_READY_TO_INSTALL becomes
+ // a terminal state, does it support completion messages?
+
+ // Completion message, localized in the specified language.
+ // TODO(omaha3): If we're going to have bundle error messages too, should the
+ // language be at bundle level? Should bundle have its own language setter?
+ [propget] HRESULT completionMessage([out, retval] BSTR*);
+
+ // Application installer result code. This is to be used as additional
+ // information only. Success/failure should be determined using errorCode.
+ // This is an error if errorCode is GOOPDATEINSTALL_E_INSTALLER_FAILED.
+ [propget] HRESULT installerResultCode([out, retval] LONG*);
+
+ // Application installer extra code.
+ [propget] HRESULT installerResultExtraCode1([out, retval] LONG*);
+
+ // A command that needs to be launched by the client after installation.
+ [propget] HRESULT postInstallLaunchCommandLine([out, retval] BSTR*);
+
+ // URL to be launched after restarting the browser.
+ [propget] HRESULT postInstallUrl([out, retval] BSTR*);
+
+ // Returns a PostInstallAction value indicating the action to be taken by the
+ // client after installation.
+ [propget] HRESULT postInstallAction([out, retval] LONG*);
+}
+
+[
+ object,
+ dual,
+ uuid(4E223325-C16B-4eeb-AEDC-19AA99A237FA),
+ helpstring("IRegistrationUpdateHook Interface"),
+ pointer_default(unique),
+]
+interface IRegistrationUpdateHook : IDispatch {
+ HRESULT UpdateRegistry([in] BSTR app_id, [in] VARIANT_BOOL is_machine);
+};
+
+[
+ object,
+ uuid(b3a47570-0a85-4aea-8270-529d47899603),
+ helpstring("ICredentialDialog Interface"),
+ pointer_default(unique),
+]
+interface ICredentialDialog : IUnknown {
+ HRESULT QueryUserForCredentials([in] ULONG_PTR owner_hwnd,
+ [in] BSTR server,
+ [in] BSTR message,
+ [out] BSTR* username,
+ [out] BSTR* password);
+};
+
+// BEGIN gupdatem interfaces.
+
+// The following interfaces are exposed as a narrower version of the
+// IGoogleUpdate3 interface from the gupdatem service. These interfaces are
+// meant for use from medium and low integrity clients.
+
+[
+ object,
+ dual,
+ uuid(494B20CF-282E-4BDD-9F5D-B70CB09D351E),
+ helpstring("IGoogleUpdate3Web Interface"),
+ pointer_default(unique),
+]
+interface IGoogleUpdate3Web : IDispatch {
+ HRESULT createAppBundleWeb([out, retval] IDispatch** app_bundle_web);
+};
+
+[
+ object,
+ uuid(2D363682-561D-4c3a-81C6-F2F82107562A),
+ helpstring("IGoogleUpdate3WebSecurity Interface"),
+ pointer_default(unique),
+]
+interface IGoogleUpdate3WebSecurity : IUnknown {
+ HRESULT setOriginURL([in] BSTR origin_url);
+};
+
+[
+ object,
+ dual,
+ uuid(DD42475D-6D46-496a-924E-BD5630B4CBBA),
+ helpstring("IAppBundleWeb Interface"),
+ pointer_default(unique),
+]
+interface IAppBundleWeb : IDispatch {
+ [id(2)] HRESULT createApp([in] BSTR app_guid,
+ [in] BSTR brand_code,
+ [in] BSTR language,
+ [in] BSTR ap);
+ [id(3)] HRESULT createInstalledApp([in] BSTR app_id);
+ [id(4)] HRESULT createAllInstalledApps();
+
+ [propget] HRESULT displayLanguage([out, retval] BSTR*);
+ [propput] HRESULT displayLanguage([in] BSTR);
+
+ [propput] HRESULT parentHWND([in] ULONG_PTR hwnd);
+
+ [propget] HRESULT length([out, retval] int* index);
+ [id(DISPID_VALUE), propget] HRESULT appWeb(
+ [in] int index, [out, retval] IDispatch** app_web);
+
+ HRESULT initialize();
+
+ HRESULT checkForUpdate();
+ HRESULT download();
+ HRESULT install();
+
+ HRESULT pause();
+ HRESULT resume();
+ HRESULT cancel();
+
+ HRESULT downloadPackage([in] BSTR app_id, [in] BSTR package_name);
+
+ [propget] HRESULT currentState([out, retval] VARIANT* current_state);
+};
+
+[
+ object,
+ dual,
+ uuid(C6398F88-69CE-44ac-B6A7-1D3E2AA46679),
+ helpstring("IAppWeb Interface"),
+ pointer_default(unique),
+]
+interface IAppWeb : IDispatch {
+ [propget] HRESULT appId([out, retval] BSTR*);
+
+ // Returns an IAppVersionWeb IDispatch object.
+ [propget] HRESULT currentVersionWeb([out, retval] IDispatch** current);
+ [propget] HRESULT nextVersionWeb([out, retval] IDispatch** next);
+
+ HRESULT cancel();
+ [propget] HRESULT currentState([out, retval] IDispatch** current_state);
+ HRESULT launch();
+ HRESULT uninstall();
+};
+
+[
+ object,
+ dual,
+ uuid(0CD01D1E-4A1C-489d-93B9-9B6672877C57),
+ helpstring("IAppVersionWeb Interface"),
+ pointer_default(unique)
+]
+interface IAppVersionWeb : IDispatch {
+ [propget] HRESULT version([out, retval] BSTR*);
+
+ // Returns the count of the Packages in the AppVersion.
+ [propget] HRESULT packageCount([out, retval] long* count);
+
+ // TODO(omaha3): Implement this after a security review.
+ // Returns an IDispatch of the Package in the AppVersion at the specified
+ // 0-based index.
+ [propget] HRESULT packageWeb([in] long index,
+ [out, retval] IDispatch** package);
+};
+
+[
+ object,
+ dual,
+ uuid(2E629606-312A-482f-9B12-2C4ABF6F0B6D),
+ helpstring("ICoCreateAsyncStatus Interface"),
+ pointer_default(unique)
+]
+interface ICoCreateAsyncStatus : IDispatch {
+ [propget] HRESULT isDone([out, retval] VARIANT_BOOL* is_done);
+ [propget] HRESULT completionHResult([out, retval] LONG* hr);
+ [propget] HRESULT createdInstance([out, retval] IDispatch** instance);
+};
+
+[
+ object,
+ uuid(DAB1D343-1B2A-47f9-B445-93DC50704BFE),
+ helpstring("ICoCreateAsync Interface"),
+ pointer_default(unique)
+]
+interface ICoCreateAsync : IUnknown {
+ HRESULT createOmahaMachineServerAsync(
+ [in] BSTR origin_url,
+ [in] BOOL create_elevated,
+ [out, retval] ICoCreateAsyncStatus** status);
+};
+
+// END gupdatem interfaces.
+
+// BEGIN Legacy google_update_idl interfaces.
+
[
object,
uuid(5B25A8DC-1780-4178-A629-6BE8B8DEFAA2),
@@ -22,7 +602,7 @@ interface IBrowserHttpRequest2 : IUnknown {
// @param request_headers HTTP request headers, if any. Can be NULL.
// @param response_headers_needed HTTP response headers that are needed.
// Should be one of the values listed here:
- // http://go/queryinfoflags
+ // http://msdn.microsoft.com/aa385351.aspx
// The input is a SAFEARRAY of DWORD. Can be a
// VT_EMPTY.
// @param response_headers HTTP response headers, returned as SAFEARRAY
@@ -66,6 +646,18 @@ interface IProcessLauncher : IUnknown {
[out] ULONG_PTR* proc_handle);
};
+[
+ object,
+ oleautomation,
+ uuid(5CCCB0EF-7073-4516-8028-4C628D0C8AAB),
+ helpstring("Google Update IOneClickProcessLauncher Interface"),
+ pointer_default(unique)
+]
+interface IOneClickProcessLauncher : IUnknown {
+ HRESULT LaunchAppCommand([in, string] const WCHAR* app_guid,
+ [in, string] const WCHAR* cmd_id);
+};
+
typedef enum {
COMPLETION_CODE_SUCCESS = 1,
COMPLETION_CODE_SUCCESS_CLOSE_UI,
@@ -77,7 +669,7 @@ typedef enum {
COMPLETION_CODE_REBOOT_NOTICE_ONLY,
COMPLETION_CODE_RESTART_BROWSER_NOTICE_ONLY,
COMPLETION_CODE_RUN_COMMAND,
-} CompletionCodes;
+} LegacyCompletionCodes;
[
object,
@@ -124,15 +716,11 @@ interface IJobObserver : IUnknown {
HRESULT OnWaitingToInstall();
HRESULT OnInstalling();
HRESULT OnPause();
- HRESULT OnComplete([in] CompletionCodes code,
+ HRESULT OnComplete([in] LegacyCompletionCodes code,
[in, string] const WCHAR* reserved);
HRESULT SetEventSink([in] IProgressWndEvents* ui_sink);
};
-// TODO(ganesh): Component story.
-// TODO(ganesh): Should CheckForUpdate be synchronous? We can avoid the
-// observer. However, it may block the UI.
-// TODO(ganesh): On-Demand Installs.
[
object,
oleautomation,
@@ -174,33 +762,144 @@ interface IGoogleUpdateCore : IUnknown
[out] ULONG_PTR* proc_handle);
};
+// END Legacy google_update_idl interfaces.
+
[
- uuid(7E6CD20B-8688-4960-96D9-B979471577B8),
+ uuid(655DD85A-3C0D-4674-9C58-AF7168C5861E),
version(1.0),
- helpstring("Google Update Type Library")
+ helpstring("Google Update 3.0 Type Library")
]
-library GoogleUpdateLib {
+library GoogleUpdate3Lib {
importlib("stdole2.tlb");
+
+ // These Interfaces are forward declared to ensure that they are described in
+ // the generated TLB file. This is required for ATL to correctly implement the
+ // corresponding IDispatch interfaces.
+ interface IGoogleUpdate3;
+ interface IAppBundle;
+ interface IApp;
+ interface IAppVersion;
+ interface IPackage;
+ interface ICurrentState;
+
+ interface IGoogleUpdate3Web;
+ interface IAppBundleWeb;
+ interface IAppWeb;
+ interface IAppVersionWeb;
+ interface ICoCreateAsyncStatus;
+
+ [
+ uuid(022105BD-948A-40c9-AB42-A3300DDF097F),
+ helpstring("GoogleUpdate3 Class for per-user applications")
+ ]
+ coclass GoogleUpdate3UserClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(4EB61BAC-A3B6-4760-9581-655041EF4D69),
+ helpstring("GoogleUpdate3 Service Class for machine applications")
+ ]
+ coclass GoogleUpdate3ServiceClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(22181302-A8A6-4f84-A541-E5CBFC70CC43),
+ helpstring("GoogleUpdate3Web for user applications")
+ ]
+ coclass GoogleUpdate3WebUserClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(8A1D4361-2C08-4700-A351-3EAA9CBFF5E4),
+ helpstring("Pass-through broker for the GoogleUpdate3WebServiceClass")
+ ]
+ coclass GoogleUpdate3WebMachineClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(534F5323-3569-4f42-919D-1E1CF93E5BF6),
+ helpstring("GoogleUpdate3Web")
+ ]
+ coclass GoogleUpdate3WebServiceClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(598FE0E5-E02D-465d-9A9D-37974A28FD42),
+ helpstring("Fallback mechanism if GoogleUpdate3WebServiceClass fails")
+ ]
+ coclass GoogleUpdate3WebMachineFallbackClass {
+ [default] interface IDispatch;
+ }
+
+ [
+ uuid(E8CF3E55-F919-49d9-ABC0-948E6CB34B9F),
+ helpstring("CurrentStateUserClass")
+ ]
+ coclass CurrentStateUserClass {
+ [default] interface ICurrentState;
+ }
+
+ [
+ uuid(9D6AA569-9F30-41ad-885A-346685C74928),
+ helpstring("CurrentStateMachineClass")
+ ]
+ coclass CurrentStateMachineClass {
+ [default] interface ICurrentState;
+ }
+
+ [
+ uuid(7DE94008-8AFD-4c70-9728-C6FBFFF6A73E),
+ helpstring("CoCreateAsyncClass")
+ ]
+ coclass CoCreateAsyncClass {
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(e67be843-bbbe-4484-95fb-05271ae86750),
+ helpstring("CredentialDialogUserClass")
+ ]
+ coclass CredentialDialogUserClass {
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(25461599-633d-42b1-84fb-7cd68d026e53),
+ helpstring("CredentialDialogMachineClass")
+ ]
+ coclass CredentialDialogMachineClass {
+ [default] interface IUnknown;
+ }
+
+ // BEGIN Legacy google_update_idl coclasses.
+
[
uuid(ABC01078-F197-4b0b-ADBC-CFE684B39C82),
helpstring("ProcessLauncherClass Class")
]
coclass ProcessLauncherClass {
- [default] interface IProcessLauncher;
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(51F9E8EF-59D7-475b-A106-C7EA6F30C119),
+ helpstring("OneClickUserProcessLauncherClass Class")
+ ]
+ coclass OneClickUserProcessLauncherClass {
+ [default] interface IOneClickProcessLauncher;
}
- // This coclass declaration exists only for the purpose of forcing
- // ::RegisterTypeLib() to register the interfaces within. This is
- // required so that we can marshal/unmarshal the interfaces using the TypeLib
- // marshaler.
[
- uuid(9564861C-3469-4c9a-956A-74D5690790E6),
- helpstring("InterfaceRegistrar Class")
+ uuid(AAD4AE2E-D834-46d4-8B09-490FAC9C722B),
+ helpstring("OneClickMachineProcessLauncherClass Class")
]
- coclass InterfaceRegistrar {
- [default] interface IBrowserHttpRequest2;
- interface IJobObserver;
- interface IProgressWndEvents;
+ coclass OneClickMachineProcessLauncherClass {
+ [default] interface IOneClickProcessLauncher;
}
[
@@ -208,15 +907,31 @@ library GoogleUpdateLib {
helpstring("OnDemand updates for per-user applications.")
]
coclass OnDemandUserAppsClass {
- [default] interface IGoogleUpdate;
+ [default] interface IUnknown;
}
[
uuid(6F8BD55B-E83D-4a47-85BE-81FFA8057A69),
- helpstring("OnDemand updates for per-machine applications.")
+ helpstring("OnDemand pass-through broker for machine applications.")
]
coclass OnDemandMachineAppsClass {
- [default] interface IGoogleUpdate;
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(9465B4B4-5216-4042-9A2C-754D3BCDC410),
+ helpstring("OnDemand updates for per-machine applications.")
+ ]
+ coclass OnDemandMachineAppsServiceClass {
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(B3D28DBD-0DFA-40e4-8071-520767BADC7E),
+ helpstring("Fallback for if OnDemandMachineAppsServiceClass fails.")
+ ]
+ coclass OnDemandMachineAppsFallbackClass {
+ [default] interface IUnknown;
}
[
@@ -225,7 +940,17 @@ library GoogleUpdateLib {
]
coclass GoogleUpdateCoreClass
{
- [default] interface IGoogleUpdateCore;
+ [default] interface IUnknown;
+ }
+
+ [
+ uuid(9B2340A0-4068-43d6-B404-32E27217859D),
+ helpstring("GoogleUpdateCore Machine Class")
+ ]
+ coclass GoogleUpdateCoreMachineClass
+ {
+ [default] interface IUnknown;
}
+ // END Legacy google_update_idl coclasses.
};
diff --git a/remoting/host/plugin/DEPS b/remoting/host/plugin/DEPS
new file mode 100644
index 0000000..7251c42
--- /dev/null
+++ b/remoting/host/plugin/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+google_update",
+]
diff --git a/remoting/host/plugin/daemon_controller_win.cc b/remoting/host/plugin/daemon_controller_win.cc
index 7fca35d..5369fbb 100644
--- a/remoting/host/plugin/daemon_controller_win.cc
+++ b/remoting/host/plugin/daemon_controller_win.cc
@@ -8,28 +8,38 @@
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
+#include "base/string16.h"
+#include "base/stringize_macros.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "base/win/scoped_bstr.h"
+#include "base/win/scoped_comptr.h"
#include "remoting/base/scoped_sc_handle_win.h"
#include "remoting/host/branding.h"
+#include "remoting/host/plugin/daemon_installer_win.h"
// MIDL-generated declarations and definitions.
#include "remoting/host/elevated_controller.h"
+using base::win::ScopedBstr;
+using base::win::ScopedComPtr;
+
namespace remoting {
namespace {
// The COM elevation moniker for the elevated controller.
-const char kElevationMoniker[] = "Elevation:Administrator!new:"
- "{430a9403-8176-4733-afdc-0b325a8fda84}";
+const char16 kDaemonControllerElevationMoniker[] =
+ TO_L_STRING("Elevation:Administrator!new:")
+ TO_L_STRING("ChromotingElevatedController.ElevatedController");
// Name of the Daemon Controller's worker thread.
const char kDaemonControllerThreadName[] = "Daemon Controller thread";
@@ -50,7 +60,7 @@ class ComThread : public base::Thread {
virtual void Init() OVERRIDE;
virtual void CleanUp() OVERRIDE;
- IDaemonControl* control_;
+ ScopedComPtr<IDaemonControl> control_;
DISALLOW_COPY_AND_ASSIGN(ComThread);
};
@@ -76,12 +86,20 @@ class DaemonControllerWin : public remoting::DaemonController {
// Converts HRESULT to the AsyncResult.
static AsyncResult HResultToAsyncResult(HRESULT hr);
+ // Procedes with the daemon configuration if the installation succeeded,
+ // otherwise reports the error.
+ void OnInstallationComplete(scoped_ptr<base::DictionaryValue> config,
+ const CompletionCallback& done_callback,
+ HRESULT result);
+
// Opens the Chromoting service returning its handle in |service_out|.
DWORD OpenService(ScopedScHandle* service_out);
// The functions that actually do the work. They should be called in
// the context of |worker_thread_|;
void DoGetConfig(const GetConfigCallback& callback);
+ void DoInstallAsNeededAndStart(scoped_ptr<base::DictionaryValue> config,
+ const CompletionCallback& done_callback);
void DoSetConfigAndStart(scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done_callback);
void DoStop(const CompletionCallback& done_callback);
@@ -89,6 +107,8 @@ class DaemonControllerWin : public remoting::DaemonController {
// The worker thread used for servicing long running operations.
ComThread worker_thread_;
+ scoped_ptr<DaemonInstallerWin> installer_;
+
DISALLOW_COPY_AND_ASSIGN(DaemonControllerWin);
};
@@ -100,8 +120,7 @@ void ComThread::Init() {
}
void ComThread::CleanUp() {
- if (control_ != NULL)
- control_->Release();
+ control_.Release();
CoUninitialize();
}
@@ -109,25 +128,24 @@ HRESULT ComThread::ActivateElevatedController(
IDaemonControl** control_out) {
// Chache the instance of Elevated Controller to prevent a UAC prompt on every
// operation.
- if (control_ == NULL) {
+ if (control_.get() == NULL) {
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;
- HRESULT hr = ::CoGetObject(ASCIIToUTF16(kElevationMoniker).c_str(),
- &bind_options,
- IID_IDaemonControl,
- reinterpret_cast<void**>(&control_));
+ HRESULT hr = ::CoGetObject(
+ kDaemonControllerElevationMoniker,
+ &bind_options,
+ IID_IDaemonControl,
+ control_.ReceiveVoid());
if (FAILED(hr)) {
- LOG(ERROR) << "Failed to create the elevated controller (error: 0x"
- << std::hex << hr << std::dec << ").";
return hr;
}
}
- *control_out = control_;
+ *control_out = control_.get();
return S_OK;
}
@@ -168,7 +186,7 @@ remoting::DaemonController::State DaemonControllerWin::GetState() {
break;
}
case ERROR_SERVICE_DOES_NOT_EXIST:
- return STATE_NOT_IMPLEMENTED;
+ return STATE_NOT_INSTALLED;
default:
return STATE_UNKNOWN;
}
@@ -187,8 +205,8 @@ void DaemonControllerWin::SetConfigAndStart(
worker_thread_.message_loop_proxy()->PostTask(
FROM_HERE, base::Bind(
- &DaemonControllerWin::DoSetConfigAndStart, base::Unretained(this),
- base::Passed(&config), done_callback));
+ &DaemonControllerWin::DoInstallAsNeededAndStart,
+ base::Unretained(this), base::Passed(&config), done_callback));
}
void DaemonControllerWin::UpdateConfig(
@@ -241,6 +259,24 @@ DaemonController::AsyncResult DaemonControllerWin::HResultToAsyncResult(
return FAILED(hr) ? RESULT_FAILED : RESULT_OK;
}
+void DaemonControllerWin::OnInstallationComplete(
+ scoped_ptr<base::DictionaryValue> config,
+ const CompletionCallback& done_callback,
+ HRESULT result) {
+ DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ if (SUCCEEDED(result)) {
+ DoSetConfigAndStart(config.Pass(), done_callback);
+ } else {
+ LOG(ERROR) << "Failed to install the Chromoting Host "
+ << "(error: 0x" << std::hex << result << std::dec << ").";
+ done_callback.Run(HResultToAsyncResult(result));
+ }
+
+ DCHECK(installer_.get() != NULL);
+ installer_.reset();
+}
+
DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) {
// Open the service and query its current state.
ScopedScHandle scmanager(
@@ -270,6 +306,8 @@ DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) {
}
void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) {
+ DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread());
+
IDaemonControl* control = NULL;
HRESULT hr = worker_thread_.ActivateElevatedController(&control);
if (FAILED(hr)) {
@@ -278,16 +316,14 @@ void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) {
}
// Get the host configuration.
- BSTR host_config = NULL;
- hr = control->GetConfig(&host_config);
+ ScopedBstr host_config;
+ hr = control->GetConfig(host_config.Receive());
if (FAILED(hr)) {
callback.Run(scoped_ptr<base::DictionaryValue>());
return;
}
- string16 file_content(static_cast<char16*>(host_config),
- ::SysStringLen(host_config));
- SysFreeString(host_config);
+ string16 file_content(static_cast<BSTR>(host_config), host_config.Length());
// Parse the string into a dictionary.
scoped_ptr<base::Value> config(
@@ -303,9 +339,44 @@ void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) {
callback.Run(scoped_ptr<base::DictionaryValue>(dictionary));
}
+void DaemonControllerWin::DoInstallAsNeededAndStart(
+ scoped_ptr<base::DictionaryValue> config,
+ const CompletionCallback& done_callback) {
+ DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread());
+
+ IDaemonControl* control = NULL;
+ HRESULT hr = worker_thread_.ActivateElevatedController(&control);
+
+ // Just configure and start the Daemon Controller if it is installed already.
+ if (SUCCEEDED(hr)) {
+ DoSetConfigAndStart(config.Pass(), done_callback);
+ return;
+ }
+
+ // Otherwise, install it if it's COM registration entry is missing.
+ if (hr == CO_E_CLASSSTRING) {
+ scoped_ptr<DaemonInstallerWin> installer = DaemonInstallerWin::Create(
+ base::Bind(&DaemonControllerWin::OnInstallationComplete,
+ base::Unretained(this),
+ base::Passed(&config),
+ done_callback));
+ if (installer.get()) {
+ DCHECK(!installer_.get());
+ installer_ = installer.Pass();
+ installer_->Install();
+ }
+ } else {
+ LOG(ERROR) << "Failed to initiate the Chromoting Host installation "
+ << "(error: 0x" << std::hex << hr << std::dec << ").";
+ done_callback.Run(HResultToAsyncResult(hr));
+ }
+}
+
void DaemonControllerWin::DoSetConfigAndStart(
scoped_ptr<base::DictionaryValue> config,
const CompletionCallback& done_callback) {
+ DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread());
+
IDaemonControl* control = NULL;
HRESULT hr = worker_thread_.ActivateElevatedController(&control);
if (FAILED(hr)) {
@@ -317,14 +388,13 @@ void DaemonControllerWin::DoSetConfigAndStart(
std::string file_content;
base::JSONWriter::Write(config.get(), &file_content);
- BSTR host_config = ::SysAllocString(UTF8ToUTF16(file_content).c_str());
+ ScopedBstr host_config(UTF8ToUTF16(file_content).c_str());
if (host_config == NULL) {
done_callback.Run(HResultToAsyncResult(E_OUTOFMEMORY));
return;
}
hr = control->SetConfig(host_config);
- ::SysFreeString(host_config);
if (FAILED(hr)) {
done_callback.Run(HResultToAsyncResult(hr));
return;
@@ -336,6 +406,8 @@ void DaemonControllerWin::DoSetConfigAndStart(
}
void DaemonControllerWin::DoStop(const CompletionCallback& done_callback) {
+ DCHECK(worker_thread_.message_loop_proxy()->BelongsToCurrentThread());
+
IDaemonControl* control = NULL;
HRESULT hr = worker_thread_.ActivateElevatedController(&control);
if (FAILED(hr)) {
diff --git a/remoting/host/plugin/daemon_installer_win.cc b/remoting/host/plugin/daemon_installer_win.cc
new file mode 100644
index 0000000..9d7e524
--- /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
diff --git a/remoting/host/plugin/daemon_installer_win.h b/remoting/host/plugin/daemon_installer_win.h
new file mode 100644
index 0000000..aeac829
--- /dev/null
+++ b/remoting/host/plugin/daemon_installer_win.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef REMOTING_HOST_DAEMON_INSTALLER_WIN_H_
+#define REMOTING_HOST_DAEMON_INSTALLER_WIN_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "remoting/host/plugin/daemon_controller.h"
+
+namespace remoting {
+
+class DaemonInstallerWin {
+ public:
+ typedef base::Callback<void (HRESULT result)> CompletionCallback;
+
+ virtual ~DaemonInstallerWin();
+
+ // Initiates download and installation of the Chromoting Host.
+ virtual void Install() = 0;
+
+ // Creates an instance of the Chromoting Host installer passing the completion
+ // callback to be called when the installation finishes. In case of an error
+ // returns NULL and passed the error code to |done|.
+ static scoped_ptr<DaemonInstallerWin> Create(CompletionCallback done);
+
+ protected:
+ DaemonInstallerWin(const CompletionCallback& done);
+
+ // Invokes the completion callback to report the installation result.
+ void Done(HRESULT result);
+
+ private:
+ // The completion callback that should be called to report the installation
+ // result.
+ CompletionCallback done_;
+
+ DISALLOW_COPY_AND_ASSIGN(DaemonInstallerWin);
+};
+
+} // namespace remoting
+
+#endif // REMOTING_HOST_DAEMON_INSTALLER_WIN_H_
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 2509c8b..bb2d586 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -554,6 +554,8 @@
'host/plugin/daemon_controller_linux.cc',
'host/plugin/daemon_controller_mac.cc',
'host/plugin/daemon_controller_win.cc',
+ 'host/plugin/daemon_installer_win.cc',
+ 'host/plugin/daemon_installer_win.h',
'host/plugin/host_log_handler.cc',
'host/plugin/host_log_handler.h',
'host/plugin/host_plugin.cc',
@@ -599,6 +601,7 @@
}], # OS=="mac"
[ 'OS=="win"', {
'dependencies': [
+ '../google_update/google_update.gyp:google_update',
'../ipc/ipc.gyp:ipc',
'remoting_elevated_controller',
'remoting_version_resources',