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 15 namespace remoting { 16 17 // Name of the Daemon Controller's worker thread. 18 const char kDaemonControllerThreadName[] = "Daemon Controller thread"; 19 20 DaemonController::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 35 DaemonController::State DaemonController::GetState() { 36 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 37 return delegate_->GetState(); 38 } 39 40 void 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 50 void 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 60 void 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 74 void 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 86 void 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 96 void 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 105 void 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 115 void 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 126 DaemonController::~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 135 void 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 143 void DaemonController::DoInstallHost(const CompletionCallback& done) { 144 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 145 146 delegate_->InstallHost(done); 147 } 148 149 void 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 158 void 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 166 void DaemonController::DoStop(const CompletionCallback& done) { 167 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 168 169 delegate_->Stop(done); 170 } 171 172 void 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 180 void 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 187 void 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 196 void 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 211 void 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 220 void 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 229 void 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 238 void DaemonController::ScheduleNext() { 239 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 240 241 pending_requests_.pop(); 242 ServiceNextRequest(); 243 } 244 245 void 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 252 void DaemonController::ServiceNextRequest() { 253 if (!pending_requests_.empty()) 254 delegate_task_runner_->PostTask(FROM_HERE, pending_requests_.front()); 255 } 256 257 } // namespace remoting 258