// // Copyright (C) 2015 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "trunks/background_command_transceiver.h" #include <base/bind.h> #include <base/callback.h> #include <base/location.h> #include <base/logging.h> #include <base/single_thread_task_runner.h> #include <base/synchronization/waitable_event.h> #include <base/threading/thread_task_runner_handle.h> namespace { // A simple callback useful when waiting for an asynchronous call. void AssignAndSignal(std::string* destination, base::WaitableEvent* event, const std::string& source) { *destination = source; event->Signal(); } // A callback which posts another |callback| to a given |task_runner|. void PostCallbackToTaskRunner( const trunks::CommandTransceiver::ResponseCallback& callback, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, const std::string& response) { base::Closure task = base::Bind(callback, response); task_runner->PostTask(FROM_HERE, task); } } // namespace namespace trunks { BackgroundCommandTransceiver::BackgroundCommandTransceiver( CommandTransceiver* next_transceiver, const scoped_refptr<base::SequencedTaskRunner>& task_runner) : next_transceiver_(next_transceiver), task_runner_(task_runner), weak_factory_(this) {} BackgroundCommandTransceiver::~BackgroundCommandTransceiver() {} void BackgroundCommandTransceiver::SendCommand( const std::string& command, const ResponseCallback& callback) { if (task_runner_.get()) { ResponseCallback background_callback = base::Bind(PostCallbackToTaskRunner, callback, base::ThreadTaskRunnerHandle::Get()); // Use SendCommandTask instead of binding to next_transceiver_ directly to // leverage weak pointer semantics. base::Closure task = base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(), command, background_callback); task_runner_->PostNonNestableTask(FROM_HERE, task); } else { next_transceiver_->SendCommand(command, callback); } } std::string BackgroundCommandTransceiver::SendCommandAndWait( const std::string& command) { if (task_runner_.get()) { std::string response; base::WaitableEvent response_ready( base::WaitableEvent::ResetPolicy::MANUAL, base::WaitableEvent::InitialState::NOT_SIGNALED); ResponseCallback callback = base::Bind(&AssignAndSignal, &response, &response_ready); // Use SendCommandTask instead of binding to next_transceiver_ directly to // leverage weak pointer semantics. base::Closure task = base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(), command, callback); task_runner_->PostNonNestableTask(FROM_HERE, task); response_ready.Wait(); return response; } else { return next_transceiver_->SendCommandAndWait(command); } } void BackgroundCommandTransceiver::SendCommandTask( const std::string& command, const ResponseCallback& callback) { next_transceiver_->SendCommand(command, callback); } } // namespace trunks