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::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 64 void 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 76 void 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 86 void 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 95 void 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 105 void 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 116 DaemonController::~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 125 void 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 133 void 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 142 void 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 150 void DaemonController::DoStop(const CompletionCallback& done) { 151 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 152 153 delegate_->Stop(done); 154 } 155 156 void 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 164 void 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 171 void 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 180 void 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 195 void 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 204 void 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 213 void 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 222 void DaemonController::ScheduleNext() { 223 DCHECK(caller_task_runner_->BelongsToCurrentThread()); 224 225 pending_requests_.pop(); 226 ServiceNextRequest(); 227 } 228 229 void 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 236 void DaemonController::ServiceNextRequest() { 237 if (!pending_requests_.empty()) 238 delegate_task_runner_->PostTask(FROM_HERE, pending_requests_.front()); 239 } 240 241 } // namespace remoting 242