普通文本  |  242行  |  7.97 KB

// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/host/setup/daemon_controller.h"

#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "base/values.h"
#include "remoting/base/auto_thread.h"
#include "remoting/base/auto_thread_task_runner.h"

namespace remoting {

// Name of the Daemon Controller's worker thread.
const char kDaemonControllerThreadName[] = "Daemon Controller thread";

DaemonController::DaemonController(scoped_ptr<Delegate> delegate)
    : caller_task_runner_(base::ThreadTaskRunnerHandle::Get()),
      delegate_(delegate.Pass()) {
  // Launch the delegate thread.
  delegate_thread_.reset(new AutoThread(kDaemonControllerThreadName));
#if defined(OS_WIN)
  delegate_thread_->SetComInitType(AutoThread::COM_INIT_STA);
  delegate_task_runner_ =
      delegate_thread_->StartWithType(base::MessageLoop::TYPE_UI);
#else
  delegate_task_runner_ =
      delegate_thread_->StartWithType(base::MessageLoop::TYPE_DEFAULT);
#endif
}

DaemonController::State DaemonController::GetState() {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());
  return delegate_->GetState();
}

void DaemonController::GetConfig(const GetConfigCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::GetConfigCallback wrapped_done = base::Bind(
      &DaemonController::InvokeConfigCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoGetConfig, this, wrapped_done);
  ServiceOrQueueRequest(request);
}

void DaemonController::SetConfigAndStart(
    scoped_ptr<base::DictionaryValue> config,
    bool consent,
    const CompletionCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::CompletionCallback wrapped_done = base::Bind(
      &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoSetConfigAndStart, this, base::Passed(&config),
      consent, wrapped_done);
  ServiceOrQueueRequest(request);
}

void DaemonController::UpdateConfig(scoped_ptr<base::DictionaryValue> config,
                                    const CompletionCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::CompletionCallback wrapped_done = base::Bind(
      &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoUpdateConfig, this, base::Passed(&config),
      wrapped_done);
  ServiceOrQueueRequest(request);
}

void DaemonController::Stop(const CompletionCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::CompletionCallback wrapped_done = base::Bind(
      &DaemonController::InvokeCompletionCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoStop, this, wrapped_done);
  ServiceOrQueueRequest(request);
}

void DaemonController::SetWindow(void* window_handle) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  base::Closure done = base::Bind(&DaemonController::ScheduleNext, this);
  base::Closure request = base::Bind(
      &DaemonController::DoSetWindow, this, window_handle, done);
  ServiceOrQueueRequest(request);
}

void DaemonController::GetVersion(const GetVersionCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::GetVersionCallback wrapped_done = base::Bind(
      &DaemonController::InvokeVersionCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoGetVersion, this, wrapped_done);
  ServiceOrQueueRequest(request);
}

void DaemonController::GetUsageStatsConsent(
    const GetUsageStatsConsentCallback& done) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  DaemonController::GetUsageStatsConsentCallback wrapped_done = base::Bind(
      &DaemonController::InvokeConsentCallbackAndScheduleNext, this, done);
  base::Closure request = base::Bind(
      &DaemonController::DoGetUsageStatsConsent, this, wrapped_done);
  ServiceOrQueueRequest(request);
}

DaemonController::~DaemonController() {
  // Make sure |delegate_| is deleted on the background thread.
  delegate_task_runner_->DeleteSoon(FROM_HERE, delegate_.release());

  // Stop the thread.
  delegate_task_runner_ = NULL;
  caller_task_runner_->DeleteSoon(FROM_HERE, delegate_thread_.release());
}

void DaemonController::DoGetConfig(const GetConfigCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  scoped_ptr<base::DictionaryValue> config = delegate_->GetConfig();
  caller_task_runner_->PostTask(FROM_HERE,
                                base::Bind(done, base::Passed(&config)));
}

void DaemonController::DoSetConfigAndStart(
    scoped_ptr<base::DictionaryValue> config,
    bool consent,
    const CompletionCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  delegate_->SetConfigAndStart(config.Pass(), consent, done);
}

void DaemonController::DoUpdateConfig(
    scoped_ptr<base::DictionaryValue> config,
    const CompletionCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  delegate_->UpdateConfig(config.Pass(), done);
}

void DaemonController::DoStop(const CompletionCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  delegate_->Stop(done);
}

void DaemonController::DoSetWindow(void* window_handle,
                                   const base::Closure& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  delegate_->SetWindow(window_handle);
  caller_task_runner_->PostTask(FROM_HERE, done);
}

void DaemonController::DoGetVersion(const GetVersionCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  std::string version = delegate_->GetVersion();
  caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, version));
}

void DaemonController::DoGetUsageStatsConsent(
    const GetUsageStatsConsentCallback& done) {
  DCHECK(delegate_task_runner_->BelongsToCurrentThread());

  DaemonController::UsageStatsConsent consent =
      delegate_->GetUsageStatsConsent();
  caller_task_runner_->PostTask(FROM_HERE, base::Bind(done, consent));
}

void DaemonController::InvokeCompletionCallbackAndScheduleNext(
    const CompletionCallback& done,
    AsyncResult result) {
  if (!caller_task_runner_->BelongsToCurrentThread()) {
    caller_task_runner_->PostTask(
        FROM_HERE,
        base::Bind(&DaemonController::InvokeCompletionCallbackAndScheduleNext,
                   this, done, result));
    return;
  }

  done.Run(result);
  ScheduleNext();
}

void DaemonController::InvokeConfigCallbackAndScheduleNext(
    const GetConfigCallback& done,
    scoped_ptr<base::DictionaryValue> config) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  done.Run(config.Pass());
  ScheduleNext();
}

void DaemonController::InvokeConsentCallbackAndScheduleNext(
    const GetUsageStatsConsentCallback& done,
    const UsageStatsConsent& consent) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  done.Run(consent);
  ScheduleNext();
}

void DaemonController::InvokeVersionCallbackAndScheduleNext(
    const GetVersionCallback& done,
    const std::string& version) {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  done.Run(version);
  ScheduleNext();
}

void DaemonController::ScheduleNext() {
  DCHECK(caller_task_runner_->BelongsToCurrentThread());

  pending_requests_.pop();
  ServiceNextRequest();
}

void DaemonController::ServiceOrQueueRequest(const base::Closure& request) {
  bool servicing_request = !pending_requests_.empty();
  pending_requests_.push(request);
  if (!servicing_request)
    ServiceNextRequest();
}

void DaemonController::ServiceNextRequest() {
  if (!pending_requests_.empty())
    delegate_task_runner_->PostTask(FROM_HERE, pending_requests_.front());
}

}  // namespace remoting