This source file includes following definitions.
- polling_timer_
- PollInstallationStatus
- OnObjectSignaled
- Done
- Create
- GetTopLevelWindow
#include "remoting/host/setup/daemon_installer_win.h"
#include <windows.h>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/process/launch.h"
#include "base/strings/string16.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/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"
#include "base/win/scoped_variant.h"
#include "base/win/windows_version.h"
#include "google_update/google_update_idl.h"
#include "remoting/base/dispatch_win.h"
#include "remoting/host/win/omaha.h"
using base::win::ScopedBstr;
using base::win::ScopedComPtr;
using base::win::ScopedVariant;
namespace {
const wchar_t kGoogleUpdate[] = L"GoogleUpdate.Update3WebMachine";
const wchar_t kGoogleUpdateElevationMoniker[] =
L"Elevation:Administrator!new:GoogleUpdate.Update3WebMachine";
const wchar_t kOmahaUpdateKeyName[] = L"Software\\Google\\Update";
const wchar_t kOmahaPathValueName[] = L"path";
const wchar_t kGoogleUpdateCommandLineFormat[] =
L"\"%ls\" /install \"bundlename=Chromoting%%20Host&appguid=%ls&"
L"appname=Chromoting%%20Host&needsadmin=True&lang=%ls\"";
const wchar_t kOmahaLanguage[] = L"en";
const wchar_t kOmahaEmpty[] = L"";
const int kOmahaPollIntervalMs = 500;
}
namespace remoting {
class DaemonComInstallerWin : public DaemonInstallerWin {
public:
DaemonComInstallerWin(const ScopedComPtr<IDispatch>& update3,
const CompletionCallback& done);
virtual void Install() OVERRIDE;
private:
void PollInstallationStatus();
ScopedVariant app_;
ScopedVariant bundle_;
ScopedComPtr<IDispatch> update3_;
base::Timer polling_timer_;
};
class DaemonCommandLineInstallerWin
: public DaemonInstallerWin,
public base::win::ObjectWatcher::Delegate {
public:
DaemonCommandLineInstallerWin(const CompletionCallback& done);
~DaemonCommandLineInstallerWin();
virtual void Install() OVERRIDE;
virtual void OnObjectSignaled(HANDLE object) OVERRIDE;
private:
base::win::ScopedHandle process_;
base::win::ObjectWatcher process_watcher_;
};
DaemonComInstallerWin::DaemonComInstallerWin(
const ScopedComPtr<IDispatch>& update3,
const CompletionCallback& done)
: DaemonInstallerWin(done),
update3_(update3),
polling_timer_(
FROM_HERE,
base::TimeDelta::FromMilliseconds(kOmahaPollIntervalMs),
base::Bind(&DaemonComInstallerWin::PollInstallationStatus,
base::Unretained(this)),
false) {
}
void DaemonComInstallerWin::Install() {
HRESULT hr = dispatch::Invoke(update3_.get(), L"createAppBundleWeb",
DISPATCH_METHOD, bundle_.Receive());
if (FAILED(hr)) {
Done(hr);
return;
}
if (bundle_.type() != VT_DISPATCH) {
Done(DISP_E_TYPEMISMATCH);
return;
}
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"initialize", DISPATCH_METHOD,
NULL);
if (FAILED(hr)) {
Done(hr);
return;
}
ScopedVariant appid(kHostOmahaAppid);
ScopedVariant empty(kOmahaEmpty);
ScopedVariant language(kOmahaLanguage);
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"createApp", DISPATCH_METHOD,
appid, empty, language, empty, NULL);
if (FAILED(hr)) {
Done(hr);
return;
}
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"checkForUpdate",
DISPATCH_METHOD, NULL);
if (FAILED(hr)) {
Done(hr);
return;
}
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"appWeb",
DISPATCH_PROPERTYGET, ScopedVariant(0), app_.Receive());
if (FAILED(hr)) {
Done(hr);
return;
}
if (app_.type() != VT_DISPATCH) {
Done(DISP_E_TYPEMISMATCH);
return;
}
PollInstallationStatus();
}
void DaemonComInstallerWin::PollInstallationStatus() {
ScopedVariant current_state;
HRESULT hr = dispatch::Invoke(V_DISPATCH(&app_), L"currentState",
DISPATCH_PROPERTYGET, current_state.Receive());
if (FAILED(hr)) {
Done(hr);
return;
}
if (current_state.type() != VT_DISPATCH) {
Done(DISP_E_TYPEMISMATCH);
return;
}
ScopedVariant state;
hr = dispatch::Invoke(V_DISPATCH(¤t_state), L"stateValue",
DISPATCH_PROPERTYGET, state.Receive());
if (state.type() != VT_I4) {
Done(DISP_E_TYPEMISMATCH);
return;
}
switch (V_I4(&state)) {
case STATE_INIT:
case STATE_WAITING_TO_CHECK_FOR_UPDATE:
case STATE_CHECKING_FOR_UPDATE:
case STATE_WAITING_TO_DOWNLOAD:
case STATE_RETRYING_DOWNLOAD:
case STATE_DOWNLOADING:
case STATE_WAITING_TO_INSTALL:
case STATE_INSTALLING:
case STATE_PAUSED:
break;
case STATE_UPDATE_AVAILABLE:
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"download",
DISPATCH_METHOD, NULL);
if (FAILED(hr)) {
Done(hr);
return;
}
break;
case STATE_DOWNLOAD_COMPLETE:
case STATE_EXTRACTING:
case STATE_APPLYING_DIFFERENTIAL_PATCH:
case STATE_READY_TO_INSTALL:
hr = dispatch::Invoke(V_DISPATCH(&bundle_), L"install",
DISPATCH_METHOD, NULL);
if (FAILED(hr)) {
Done(hr);
return;
}
break;
case STATE_INSTALL_COMPLETE:
case STATE_NO_UPDATE:
Done(S_OK);
return;
case STATE_ERROR: {
ScopedVariant error_code;
hr = dispatch::Invoke(V_DISPATCH(¤t_state), L"errorCode",
DISPATCH_PROPERTYGET, error_code.Receive());
if (FAILED(hr)) {
Done(hr);
return;
}
if (error_code.type() != VT_UI4) {
Done(DISP_E_TYPEMISMATCH);
return;
}
Done(V_UI4(&error_code));
return;
}
default:
LOG(ERROR) << "Unknown bundle state: " << V_I4(&state) << ".";
Done(E_FAIL);
return;
}
polling_timer_.Reset();
}
DaemonCommandLineInstallerWin::DaemonCommandLineInstallerWin(
const CompletionCallback& done) : DaemonInstallerWin(done) {
}
DaemonCommandLineInstallerWin::~DaemonCommandLineInstallerWin() {
process_watcher_.StopWatching();
}
void DaemonCommandLineInstallerWin::Install() {
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;
}
std::wstring google_update;
result = update_key.ReadValue(kOmahaPathValueName, &google_update);
if (result != ERROR_SUCCESS) {
Done(HRESULT_FROM_WIN32(result));
return;
}
base::string16 command_line = base::WideToUTF16(
base::StringPrintf(kGoogleUpdateCommandLineFormat,
google_update.c_str(),
kHostOmahaAppid,
kOmahaLanguage));
base::LaunchOptions options;
if (!base::LaunchProcess(command_line, options, &process_)) {
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) {
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) {
CompletionCallback done = done_;
done_.Reset();
done.Run(result);
}
scoped_ptr<DaemonInstallerWin> DaemonInstallerWin::Create(
HWND window_handle,
CompletionCallback done) {
HRESULT result = E_FAIL;
ScopedComPtr<IDispatch> update3;
if (base::win::GetVersion() < base::win::VERSION_VISTA) {
CLSID class_id;
result = CLSIDFromProgID(kGoogleUpdate, &class_id);
if (SUCCEEDED(result)) {
result = CoCreateInstance(class_id,
NULL,
CLSCTX_LOCAL_SERVER,
IID_IDispatch,
update3.ReceiveVoid());
}
} else {
BIND_OPTS3 bind_options;
memset(&bind_options, 0, sizeof(bind_options));
bind_options.cbStruct = sizeof(bind_options);
bind_options.hwnd = GetTopLevelWindow(window_handle);
bind_options.dwClassContext = CLSCTX_LOCAL_SERVER;
result = CoGetObject(kGoogleUpdateElevationMoniker,
&bind_options,
IID_IDispatch,
update3.ReceiveVoid());
}
if (SUCCEEDED(result)) {
return scoped_ptr<DaemonInstallerWin>(
new DaemonComInstallerWin(update3, done));
} else if (result == CO_E_CLASSSTRING) {
return scoped_ptr<DaemonInstallerWin>(
new DaemonCommandLineInstallerWin(done));
} else {
done.Run(result);
return scoped_ptr<DaemonInstallerWin>();
}
}
HWND GetTopLevelWindow(HWND window) {
if (window == NULL) {
return NULL;
}
for (;;) {
LONG style = GetWindowLong(window, GWL_STYLE);
if ((style & WS_OVERLAPPEDWINDOW) == WS_OVERLAPPEDWINDOW ||
(style & WS_POPUP) == WS_POPUP) {
return window;
}
HWND parent = GetAncestor(window, GA_PARENT);
if (parent == NULL) {
return window;
}
window = parent;
}
}
}