background_command_transceiver.cc revision 80c739e10fd606b24e2656cad6e566c66bb218d4
1// Copyright 2015 The Chromium OS 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 "trunks/background_command_transceiver.h"
6
7#include <base/bind.h>
8#include <base/callback.h>
9#include <base/location.h>
10#include <base/logging.h>
11#include <base/message_loop/message_loop_proxy.h>
12#include <base/synchronization/waitable_event.h>
13
14namespace {
15
16// A simple callback useful when waiting for an asynchronous call.
17void AssignAndSignal(std::string* destination,
18                     base::WaitableEvent* event,
19                     const std::string& source) {
20  *destination = source;
21  event->Signal();
22}
23
24// A callback which posts another |callback| to a given |message_loop|.
25void PostCallbackToMessageLoop(
26    const trunks::CommandTransceiver::ResponseCallback& callback,
27    scoped_refptr<base::MessageLoopProxy> message_loop,
28    const std::string& response) {
29  base::Closure task = base::Bind(callback, response);
30  message_loop->PostTask(FROM_HERE, task);
31}
32
33}  // namespace
34
35namespace trunks {
36
37BackgroundCommandTransceiver::BackgroundCommandTransceiver(
38    CommandTransceiver* next_transceiver,
39    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
40    : next_transceiver_(next_transceiver),
41      task_runner_(task_runner),
42      weak_factory_(this) {}
43
44BackgroundCommandTransceiver::~BackgroundCommandTransceiver() {}
45
46void BackgroundCommandTransceiver::SendCommand(
47    const std::string& command,
48    const ResponseCallback& callback) {
49  if (task_runner_.get()) {
50    ResponseCallback background_callback = base::Bind(
51        PostCallbackToMessageLoop,
52        callback,
53        base::MessageLoopProxy::current());
54    // Use SendCommandTask instead of binding to next_transceiver_ directly to
55    // leverage weak pointer semantics.
56    base::Closure task = base::Bind(
57        &BackgroundCommandTransceiver::SendCommandTask,
58        GetWeakPtr(),
59        command,
60        background_callback);
61    task_runner_->PostNonNestableTask(FROM_HERE, task);
62  } else {
63    next_transceiver_->SendCommand(command, callback);
64  }
65}
66
67std::string BackgroundCommandTransceiver::SendCommandAndWait(
68    const std::string& command) {
69  if (task_runner_.get()) {
70    std::string response;
71    base::WaitableEvent response_ready(true,    // manual_reset
72                                       false);  // initially_signaled
73    ResponseCallback callback =
74        base::Bind(&AssignAndSignal, &response, &response_ready);
75    // Use SendCommandTask instead of binding to next_transceiver_ directly to
76    // leverage weak pointer semantics.
77    base::Closure task = base::Bind(
78        &BackgroundCommandTransceiver::SendCommandTask,
79        GetWeakPtr(),
80        command,
81        callback);
82    task_runner_->PostNonNestableTask(FROM_HERE, task);
83    response_ready.Wait();
84    return response;
85  } else {
86    return next_transceiver_->SendCommandAndWait(command);
87  }
88}
89
90void BackgroundCommandTransceiver::SendCommandTask(
91    const std::string& command,
92    const ResponseCallback& callback) {
93  next_transceiver_->SendCommand(command, callback);
94}
95
96}  // namespace trunks
97