1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "remoting/host/setup/daemon_controller.h" 6 7#include "base/bind.h" 8#include "base/location.h" 9#include "base/single_thread_task_runner.h" 10#include "base/thread_task_runner_handle.h" 11#include "base/values.h" 12#include "remoting/base/auto_thread.h" 13#include "remoting/base/auto_thread_task_runner.h" 14 15namespace remoting { 16 17// Name of the Daemon Controller's worker thread. 18const char kDaemonControllerThreadName[] = "Daemon Controller thread"; 19 20DaemonController::DaemonController(scoped_ptr<Delegate> delegate) 21 : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()), 22 delegate_(delegate.Pass()) { 23 // Launch the delegate thread. 24 delegate_thread_.reset(new AutoThread(kDaemonControllerThreadName)); 25#if defined(OS_WIN) 26 delegate_thread_->SetComInitType(AutoThread::COM_INIT_STA); 27 delegate_task_runner_ = 28 delegate_thread_->StartWithType(base::MessageLoop::TYPE_UI); 29#else 30 delegate_task_runner_ = 31 delegate_thread_->StartWithType(base::MessageLoop::TYPE_DEFAULT); 32#endif 33} 34 35DaemonController::State DaemonController::GetState() { 36 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 37 return delegate_->GetState(); 38} 39 40void DaemonController::GetConfig(const GetConfigCallback& done) { 41 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 42 43 DaemonController::GetConfigCallback wrapped_done = base::Bind( 44 &DaemonController::InvokeConfigCallbackAndScheduleNext, this, done); 45 base::Closure request = base::Bind( 46 &DaemonController::DoGetConfig, this, wrapped_done); 47 ServiceOrQueueRequest(request); 48} 49 50void DaemonController::InstallHost(const CompletionCallback& done) { 51 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 52 53 DaemonController::CompletionCallback wrapped_done = base::Bind( 54 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 55 base::Closure request = base::Bind( 56 &DaemonController::DoInstallHost, this, wrapped_done); 57 ServiceOrQueueRequest(request); 58} 59 60void DaemonController::SetConfigAndStart( 61 scoped_ptr<base::DictionaryValue> config, 62 bool consent, 63 const CompletionCallback& done) { 64 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 65 66 DaemonController::CompletionCallback wrapped_done = base::Bind( 67 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 68 base::Closure request = base::Bind( 69 &DaemonController::DoSetConfigAndStart, this, base::Passed(&config), 70 consent, wrapped_done); 71 ServiceOrQueueRequest(request); 72} 73 74void DaemonController::UpdateConfig(scoped_ptr<base::DictionaryValue> config, 75 const CompletionCallback& done) { 76 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 77 78 DaemonController::CompletionCallback wrapped_done = base::Bind( 79 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 80 base::Closure request = base::Bind( 81 &DaemonController::DoUpdateConfig, this, base::Passed(&config), 82 wrapped_done); 83 ServiceOrQueueRequest(request); 84} 85 86void DaemonController::Stop(const CompletionCallback& done) { 87 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 88 89 DaemonController::CompletionCallback wrapped_done = base::Bind( 90 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 91 base::Closure request = base::Bind( 92 &DaemonController::DoStop, this, wrapped_done); 93 ServiceOrQueueRequest(request); 94} 95 96void DaemonController::SetWindow(void* window_handle) { 97 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 98 99 base::Closure done = base::Bind(&DaemonController::ScheduleNext, this); 100 base::Closure request = base::Bind( 101 &DaemonController::DoSetWindow, this, window_handle, done); 102 ServiceOrQueueRequest(request); 103} 104 105void DaemonController::GetVersion(const GetVersionCallback& done) { 106 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 107 108 DaemonController::GetVersionCallback wrapped_done = base::Bind( 109 &DaemonController::InvokeVersionCallbackAndScheduleNext, this, done); 110 base::Closure request = base::Bind( 111 &DaemonController::DoGetVersion, this, wrapped_done); 112 ServiceOrQueueRequest(request); 113} 114 115void DaemonController::GetUsageStatsConsent( 116 const GetUsageStatsConsentCallback& done) { 117 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 118 119 DaemonController::GetUsageStatsConsentCallback wrapped_done = base::Bind( 120 &DaemonController::InvokeConsentCallbackAndScheduleNext, this, done); 121 base::Closure request = base::Bind( 122 &DaemonController::DoGetUsageStatsConsent, this, wrapped_done); 123 ServiceOrQueueRequest(request); 124} 125 126DaemonController::~DaemonController() { 127 // Make sure |delegate_| is deleted on the background thread. 128 delegate_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); 129 130 // Stop the thread. 131 delegate_task_runner_ = NULL; 132 caller_task_runner_->DeleteSoon(FROM_HERE, delegate_thread_.release()); 133} 134 135void DaemonController::DoGetConfig(const GetConfigCallback& done) { 136 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 137 138 scoped_ptr<base::DictionaryValue> config = delegate_->GetConfig(); 139 caller_task_runner_->PostTask(FROM_HERE, 140 base::Bind(done, base::Passed(&config))); 141} 142 143void DaemonController::DoInstallHost(const CompletionCallback& done) { 144 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 145 146 delegate_->InstallHost(done); 147} 148 149void DaemonController::DoSetConfigAndStart( 150 scoped_ptr<base::DictionaryValue> config, 151 bool consent, 152 const CompletionCallback& done) { 153 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 154 155 delegate_->SetConfigAndStart(config.Pass(), consent, done); 156} 157 158void DaemonController::DoUpdateConfig( 159 scoped_ptr<base::DictionaryValue> config, 160 const CompletionCallback& done) { 161 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 162 163 delegate_->UpdateConfig(config.Pass(), done); 164} 165 166void DaemonController::DoStop(const CompletionCallback& done) { 167 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 168 169 delegate_->Stop(done); 170} 171 172void DaemonController::DoSetWindow(void* window_handle, 173 const base::Closure& done) { 174 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 175 176 delegate_->SetWindow(window_handle); 177 caller_task_runner_->PostTask(FROM_HERE, done); 178} 179 180void DaemonController::DoGetVersion(const GetVersionCallback& done) { 181 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 182 183 std::string version = delegate_->GetVersion(); 184 caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, version)); 185} 186 187void DaemonController::DoGetUsageStatsConsent( 188 const GetUsageStatsConsentCallback& done) { 189 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 190 191 DaemonController::UsageStatsConsent consent = 192 delegate_->GetUsageStatsConsent(); 193 caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, consent)); 194} 195 196void DaemonController::InvokeCompletionCallbackAndScheduleNext( 197 const CompletionCallback& done, 198 AsyncResult result) { 199 if (!caller_task_runner_->BelongsToCurrentThread()) { 200 caller_task_runner_->PostTask( 201 FROM_HERE, 202 base::Bind(&DaemonController::InvokeCompletionCallbackAndScheduleNext, 203 this, done, result)); 204 return; 205 } 206 207 done.Run(result); 208 ScheduleNext(); 209} 210 211void DaemonController::InvokeConfigCallbackAndScheduleNext( 212 const GetConfigCallback& done, 213 scoped_ptr<base::DictionaryValue> config) { 214 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 215 216 done.Run(config.Pass()); 217 ScheduleNext(); 218} 219 220void DaemonController::InvokeConsentCallbackAndScheduleNext( 221 const GetUsageStatsConsentCallback& done, 222 const UsageStatsConsent& consent) { 223 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 224 225 done.Run(consent); 226 ScheduleNext(); 227} 228 229void DaemonController::InvokeVersionCallbackAndScheduleNext( 230 const GetVersionCallback& done, 231 const std::string& version) { 232 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 233 234 done.Run(version); 235 ScheduleNext(); 236} 237 238void DaemonController::ScheduleNext() { 239 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 240 241 pending_requests_.pop(); 242 ServiceNextRequest(); 243} 244 245void DaemonController::ServiceOrQueueRequest(const base::Closure& request) { 246 bool servicing_request = !pending_requests_.empty(); 247 pending_requests_.push(request); 248 if (!servicing_request) 249 ServiceNextRequest(); 250} 251 252void DaemonController::ServiceNextRequest() { 253 if (!pending_requests_.empty()) 254 delegate_task_runner_->PostTask(FROM_HERE, pending_requests_.front()); 255} 256 257} // namespace remoting 258