diff options
-rw-r--r-- | chrome/browser/google/google_update.cc | 2 | ||||
-rw-r--r-- | google_update/README.chromium | 25 | ||||
-rw-r--r-- | google_update/google_update_idl.idl | 783 | ||||
-rw-r--r-- | remoting/host/plugin/DEPS | 3 | ||||
-rw-r--r-- | remoting/host/plugin/daemon_controller_win.cc | 118 | ||||
-rw-r--r-- | remoting/host/plugin/daemon_installer_win.cc | 368 | ||||
-rw-r--r-- | remoting/host/plugin/daemon_installer_win.h | 47 | ||||
-rw-r--r-- | remoting/remoting.gyp | 3 |
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', |