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::SetConfigAndStart( 51 scoped_ptr<base::DictionaryValue> config, 52 bool consent, 53 const CompletionCallback& done) { 54 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 55 56 DaemonController::CompletionCallback wrapped_done = base::Bind( 57 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 58 base::Closure request = base::Bind( 59 &DaemonController::DoSetConfigAndStart, this, base::Passed(&config), 60 consent, wrapped_done); 61 ServiceOrQueueRequest(request); 62} 63 64void DaemonController::UpdateConfig(scoped_ptr<base::DictionaryValue> config, 65 const CompletionCallback& done) { 66 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 67 68 DaemonController::CompletionCallback wrapped_done = base::Bind( 69 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 70 base::Closure request = base::Bind( 71 &DaemonController::DoUpdateConfig, this, base::Passed(&config), 72 wrapped_done); 73 ServiceOrQueueRequest(request); 74} 75 76void DaemonController::Stop(const CompletionCallback& done) { 77 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 78 79 DaemonController::CompletionCallback wrapped_done = base::Bind( 80 &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done); 81 base::Closure request = base::Bind( 82 &DaemonController::DoStop, this, wrapped_done); 83 ServiceOrQueueRequest(request); 84} 85 86void DaemonController::SetWindow(void* window_handle) { 87 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 88 89 base::Closure done = base::Bind(&DaemonController::ScheduleNext, this); 90 base::Closure request = base::Bind( 91 &DaemonController::DoSetWindow, this, window_handle, done); 92 ServiceOrQueueRequest(request); 93} 94 95void DaemonController::GetVersion(const GetVersionCallback& done) { 96 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 97 98 DaemonController::GetVersionCallback wrapped_done = base::Bind( 99 &DaemonController::InvokeVersionCallbackAndScheduleNext, this, done); 100 base::Closure request = base::Bind( 101 &DaemonController::DoGetVersion, this, wrapped_done); 102 ServiceOrQueueRequest(request); 103} 104 105void DaemonController::GetUsageStatsConsent( 106 const GetUsageStatsConsentCallback& done) { 107 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 108 109 DaemonController::GetUsageStatsConsentCallback wrapped_done = base::Bind( 110 &DaemonController::InvokeConsentCallbackAndScheduleNext, this, done); 111 base::Closure request = base::Bind( 112 &DaemonController::DoGetUsageStatsConsent, this, wrapped_done); 113 ServiceOrQueueRequest(request); 114} 115 116DaemonController::~DaemonController() { 117 // Make sure |delegate_| is deleted on the background thread. 118 delegate_task_runner_->DeleteSoon(FROM_HERE, delegate_.release()); 119 120 // Stop the thread. 121 delegate_task_runner_ = NULL; 122 caller_task_runner_->DeleteSoon(FROM_HERE, delegate_thread_.release()); 123} 124 125void DaemonController::DoGetConfig(const GetConfigCallback& done) { 126 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 127 128 scoped_ptr<base::DictionaryValue> config = delegate_->GetConfig(); 129 caller_task_runner_->PostTask(FROM_HERE, 130 base::Bind(done, base::Passed(&config))); 131} 132 133void DaemonController::DoSetConfigAndStart( 134 scoped_ptr<base::DictionaryValue> config, 135 bool consent, 136 const CompletionCallback& done) { 137 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 138 139 delegate_->SetConfigAndStart(config.Pass(), consent, done); 140} 141 142void DaemonController::DoUpdateConfig( 143 scoped_ptr<base::DictionaryValue> config, 144 const CompletionCallback& done) { 145 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 146 147 delegate_->UpdateConfig(config.Pass(), done); 148} 149 150void DaemonController::DoStop(const CompletionCallback& done) { 151 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 152 153 delegate_->Stop(done); 154} 155 156void DaemonController::DoSetWindow(void* window_handle, 157 const base::Closure& done) { 158 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 159 160 delegate_->SetWindow(window_handle); 161 caller_task_runner_->PostTask(FROM_HERE, done); 162} 163 164void DaemonController::DoGetVersion(const GetVersionCallback& done) { 165 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 166 167 std::string version = delegate_->GetVersion(); 168 caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, version)); 169} 170 171void DaemonController::DoGetUsageStatsConsent( 172 const GetUsageStatsConsentCallback& done) { 173 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 174 175 DaemonController::UsageStatsConsent consent = 176 delegate_->GetUsageStatsConsent(); 177 caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, consent)); 178} 179 180void DaemonController::InvokeCompletionCallbackAndScheduleNext( 181 const CompletionCallback& done, 182 AsyncResult result) { 183 if (!caller_task_runner_->BelongsToCurrentThread()) { 184 caller_task_runner_->PostTask( 185 FROM_HERE, 186 base::Bind(&DaemonController::InvokeCompletionCallbackAndScheduleNext, 187 this, done, result)); 188 return; 189 } 190 191 done.Run(result); 192 ScheduleNext(); 193} 194 195void DaemonController::InvokeConfigCallbackAndScheduleNext( 196 const GetConfigCallback& done, 197 scoped_ptr<base::DictionaryValue> config) { 198 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 199 200 done.Run(config.Pass()); 201 ScheduleNext(); 202} 203 204void DaemonController::InvokeConsentCallbackAndScheduleNext( 205 const GetUsageStatsConsentCallback& done, 206 const UsageStatsConsent& consent) { 207 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 208 209 done.Run(consent); 210 ScheduleNext(); 211} 212 213void DaemonController::InvokeVersionCallbackAndScheduleNext( 214 const GetVersionCallback& done, 215 const std::string& version) { 216 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 217 218 done.Run(version); 219 ScheduleNext(); 220} 221 222void DaemonController::ScheduleNext() { 223 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 224 225 pending_requests_.pop(); 226 ServiceNextRequest(); 227} 228 229void DaemonController::ServiceOrQueueRequest(const base::Closure& request) { 230 bool servicing_request = !pending_requests_.empty(); 231 pending_requests_.push(request); 232 if (!servicing_request) 233 ServiceNextRequest(); 234} 235 236void DaemonController::ServiceNextRequest() { 237 if (!pending_requests_.empty()) 238 delegate_task_runner_->PostTask(FROM_HERE, pending_requests_.front()); 239} 240 241} // namespace remoting 242