Chromium Code Reviews| Index: remoting/host/plugin/daemon_controller_win.cc |
| diff --git a/remoting/host/plugin/daemon_controller_win.cc b/remoting/host/plugin/daemon_controller_win.cc |
| index 7fca35d897bc0d71ddf06a45f4a26fe67720dac7..11c00e01aeb37c35104532ee5917f9928fe943ea 100644 |
| --- a/remoting/host/plugin/daemon_controller_win.cc |
| +++ b/remoting/host/plugin/daemon_controller_win.cc |
| @@ -14,22 +14,29 @@ |
| #include "base/json/json_reader.h" |
| #include "base/json/json_writer.h" |
| #include "base/logging.h" |
| +#include "base/synchronization/lock.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 char kDaemonControllerElevationMoniker[] = "Elevation:Administrator!new:" |
| + "ChromotingElevatedController.ElevatedController"; |
| // Name of the Daemon Controller's worker thread. |
| const char kDaemonControllerThreadName[] = "Daemon Controller thread"; |
| @@ -50,7 +57,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 +83,18 @@ 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(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 DoInstall(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 +102,13 @@ class DaemonControllerWin : public remoting::DaemonController { |
| // The worker thread used for servicing long running operations. |
| ComThread worker_thread_; |
| + // The lock protecting the data members below. |
| + base::Lock lock_; |
| + |
| + scoped_ptr<base::DictionaryValue> config_; |
| + CompletionCallback done_callback_; |
|
Sergey Ulanov
2012/04/07 18:09:21
Since this is used only during installation maybe
alexeypa (please no reviews)
2012/04/09 20:24:11
It was removed from the class.
|
| + 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( |
| + ASCIIToUTF16(kDaemonControllerElevationMoniker).c_str(), |
| + &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,7 +205,7 @@ void DaemonControllerWin::SetConfigAndStart( |
| worker_thread_.message_loop_proxy()->PostTask( |
| FROM_HERE, base::Bind( |
| - &DaemonControllerWin::DoSetConfigAndStart, base::Unretained(this), |
| + &DaemonControllerWin::DoInstall, base::Unretained(this), |
| base::Passed(&config), done_callback)); |
| } |
| @@ -241,6 +259,26 @@ DaemonController::AsyncResult DaemonControllerWin::HResultToAsyncResult( |
| return FAILED(hr) ? RESULT_FAILED : RESULT_OK; |
| } |
| +void DaemonControllerWin::OnInstallationComplete(HRESULT result) { |
| + scoped_ptr<base::DictionaryValue> config; |
| + CompletionCallback done_callback; |
| + |
| + { |
| + base::AutoLock lock(lock_); |
| + installer_.reset(); |
| + std::swap(done_callback, done_callback_); |
| + config = config_.Pass(); |
| + } |
| + |
| + 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)); |
| + } |
| +} |
| + |
| DWORD DaemonControllerWin::OpenService(ScopedScHandle* service_out) { |
| // Open the service and query its current state. |
| ScopedScHandle scmanager( |
| @@ -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,6 +339,41 @@ void DaemonControllerWin::DoGetConfig(const GetConfigCallback& callback) { |
| callback.Run(scoped_ptr<base::DictionaryValue>(dictionary)); |
| } |
| +void DaemonControllerWin::DoInstall(scoped_ptr<base::DictionaryValue> config, |
|
Sergey Ulanov
2012/04/07 18:09:21
Since this method installs the host only if it isn
alexeypa (please no reviews)
2012/04/09 20:24:11
Renamed to DoInstallAsNeededAndStart to preserve "
|
| + const CompletionCallback& done_callback) { |
| + 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) { |
| + base::AutoLock lock(lock_); |
| + DCHECK(!config_.get()); |
| + DCHECK(!installer_.get()); |
| + |
| + hr = DaemonInstallerWin::Create(&installer_); |
| + if (SUCCEEDED(hr)) { |
| + config_ = config.Pass(); |
|
Sergey Ulanov
2012/04/07 18:09:21
Do we really need to store these values as class m
alexeypa (please no reviews)
2012/04/09 20:24:11
Done.
I kept installer_ as a class member (instea
|
| + done_callback_ = done_callback; |
| + } |
| + } |
| + |
| + // Run the installer or report the error if any. |
| + if (SUCCEEDED(hr)) { |
| + installer_->Install(base::Bind(&DaemonControllerWin::OnInstallationComplete, |
| + base::Unretained(this))); |
|
Sergey Ulanov
2012/04/07 18:09:21
nit: not indented properly
alexeypa (please no reviews)
2012/04/09 20:24:11
Done.
|
| + } 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) { |
| @@ -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; |