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 
27 namespace {
28 
29 // A simple callback useful when waiting for an asynchronous call.
AssignAndSignal(std::string * destination,base::WaitableEvent * event,const std::string & source)30 void 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|.
PostCallbackToTaskRunner(const trunks::CommandTransceiver::ResponseCallback & callback,const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,const std::string & response)38 void 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 
48 namespace trunks {
49 
BackgroundCommandTransceiver(CommandTransceiver * next_transceiver,const scoped_refptr<base::SequencedTaskRunner> & task_runner)50 BackgroundCommandTransceiver::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 
~BackgroundCommandTransceiver()57 BackgroundCommandTransceiver::~BackgroundCommandTransceiver() {}
58 
SendCommand(const std::string & command,const ResponseCallback & callback)59 void 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 
SendCommandAndWait(const std::string & command)77 std::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 
SendCommandTask(const std::string & command,const ResponseCallback & callback)99 void BackgroundCommandTransceiver::SendCommandTask(
100     const std::string& command,
101     const ResponseCallback& callback) {
102   next_transceiver_->SendCommand(command, callback);
103 }
104 
105 }  // namespace trunks
106