background_command_transceiver.cc revision 9c6f6b29325bb706ba3b2673a4b6d81d4daee378
1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trunks/background_command_transceiver.h"
18
19#include <base/bind.h>
20#include <base/callback.h>
21#include <base/location.h>
22#include <base/logging.h>
23#include <base/single_thread_task_runner.h>
24#include <base/synchronization/waitable_event.h>
25#include <base/threading/thread_task_runner_handle.h>
26
27namespace {
28
29// A simple callback useful when waiting for an asynchronous call.
30void AssignAndSignal(std::string* destination,
31                     base::WaitableEvent* event,
32                     const std::string& source) {
33  *destination = source;
34  event->Signal();
35}
36
37// A callback which posts another |callback| to a given |task_runner|.
38void PostCallbackToTaskRunner(
39    const trunks::CommandTransceiver::ResponseCallback& callback,
40    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
41    const std::string& response) {
42  base::Closure task = base::Bind(callback, response);
43  task_runner->PostTask(FROM_HERE, task);
44}
45
46}  // namespace
47
48namespace trunks {
49
50BackgroundCommandTransceiver::BackgroundCommandTransceiver(
51    CommandTransceiver* next_transceiver,
52    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
53    : next_transceiver_(next_transceiver),
54      task_runner_(task_runner),
55      weak_factory_(this) {}
56
57BackgroundCommandTransceiver::~BackgroundCommandTransceiver() {}
58
59void BackgroundCommandTransceiver::SendCommand(
60    const std::string& command,
61    const ResponseCallback& callback) {
62  if (task_runner_.get()) {
63    ResponseCallback background_callback =
64        base::Bind(PostCallbackToTaskRunner, callback,
65                   base::ThreadTaskRunnerHandle::Get());
66    // Use SendCommandTask instead of binding to next_transceiver_ directly to
67    // leverage weak pointer semantics.
68    base::Closure task =
69        base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(),
70                   command, background_callback);
71    task_runner_->PostNonNestableTask(FROM_HERE, task);
72  } else {
73    next_transceiver_->SendCommand(command, callback);
74  }
75}
76
77std::string BackgroundCommandTransceiver::SendCommandAndWait(
78    const std::string& command) {
79  if (task_runner_.get()) {
80    std::string response;
81    base::WaitableEvent response_ready(
82        base::WaitableEvent::ResetPolicy::MANUAL,
83        base::WaitableEvent::InitialState::NOT_SIGNALED);
84    ResponseCallback callback =
85        base::Bind(&AssignAndSignal, &response, &response_ready);
86    // Use SendCommandTask instead of binding to next_transceiver_ directly to
87    // leverage weak pointer semantics.
88    base::Closure task =
89        base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(),
90                   command, callback);
91    task_runner_->PostNonNestableTask(FROM_HERE, task);
92    response_ready.Wait();
93    return response;
94  } else {
95    return next_transceiver_->SendCommandAndWait(command);
96  }
97}
98
99void BackgroundCommandTransceiver::SendCommandTask(
100    const std::string& command,
101    const ResponseCallback& callback) {
102  next_transceiver_->SendCommand(command, callback);
103}
104
105}  // namespace trunks
106