1bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
2bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Copyright (C) 2015 The Android Open Source Project
3bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
4bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Licensed under the Apache License, Version 2.0 (the "License");
5bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// you may not use this file except in compliance with the License.
6bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// You may obtain a copy of the License at
7bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
8bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//      http://www.apache.org/licenses/LICENSE-2.0
9bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
10bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// Unless required by applicable law or agreed to in writing, software
11bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// distributed under the License is distributed on an "AS IS" BASIS,
12bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// See the License for the specific language governing permissions and
14bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi// limitations under the License.
15bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi//
1680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
1780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include "trunks/background_command_transceiver.h"
1880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
1980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include <base/bind.h>
2080c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include <base/callback.h>
2180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include <base/location.h>
2280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include <base/logging.h>
237e763a9434e12c7980529980de5f8eced22b310aAlex Vakulenko#include <base/single_thread_task_runner.h>
2480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn#include <base/synchronization/waitable_event.h>
2530c921db09d27768acc1ea0d8b6a9c8e814f931aLuis Hector Chavez#include <base/threading/thread_task_runner_handle.h>
2680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
2780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnnamespace {
2880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
2980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn// A simple callback useful when waiting for an asynchronous call.
3080c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnvoid AssignAndSignal(std::string* destination,
3180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn                     base::WaitableEvent* event,
3280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn                     const std::string& source) {
3380c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  *destination = source;
3480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  event->Signal();
3580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}
3680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
377e763a9434e12c7980529980de5f8eced22b310aAlex Vakulenko// A callback which posts another |callback| to a given |task_runner|.
387e763a9434e12c7980529980de5f8eced22b310aAlex Vakulenkovoid PostCallbackToTaskRunner(
3980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const trunks::CommandTransceiver::ResponseCallback& callback,
409c6f6b29325bb706ba3b2673a4b6d81d4daee378Chih-Hung Hsieh    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
4180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const std::string& response) {
4280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  base::Closure task = base::Bind(callback, response);
437e763a9434e12c7980529980de5f8eced22b310aAlex Vakulenko  task_runner->PostTask(FROM_HERE, task);
4480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}
4580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
4680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}  // namespace
4780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
4880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnnamespace trunks {
4980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
5080c739e10fd606b24e2656cad6e566c66bb218d4Darren KrahnBackgroundCommandTransceiver::BackgroundCommandTransceiver(
5180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    CommandTransceiver* next_transceiver,
5280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
5380c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    : next_transceiver_(next_transceiver),
5480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn      task_runner_(task_runner),
5580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn      weak_factory_(this) {}
5680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
5780c739e10fd606b24e2656cad6e566c66bb218d4Darren KrahnBackgroundCommandTransceiver::~BackgroundCommandTransceiver() {}
5880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
5980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnvoid BackgroundCommandTransceiver::SendCommand(
6080c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const std::string& command,
6180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const ResponseCallback& callback) {
6280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  if (task_runner_.get()) {
634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    ResponseCallback background_callback =
644dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        base::Bind(PostCallbackToTaskRunner, callback,
654dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                   base::ThreadTaskRunnerHandle::Get());
6680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    // Use SendCommandTask instead of binding to next_transceiver_ directly to
6780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    // leverage weak pointer semantics.
684dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    base::Closure task =
694dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(),
704dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                   command, background_callback);
7180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    task_runner_->PostNonNestableTask(FROM_HERE, task);
7280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  } else {
7380c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    next_transceiver_->SendCommand(command, callback);
7480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  }
7580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}
7680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
7780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnstd::string BackgroundCommandTransceiver::SendCommandAndWait(
7880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const std::string& command) {
7980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  if (task_runner_.get()) {
8080c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    std::string response;
8139e701593e712adf6edfa029710dfb7af376ad4cLuis Hector Chavez    base::WaitableEvent response_ready(
8239e701593e712adf6edfa029710dfb7af376ad4cLuis Hector Chavez        base::WaitableEvent::ResetPolicy::MANUAL,
8339e701593e712adf6edfa029710dfb7af376ad4cLuis Hector Chavez        base::WaitableEvent::InitialState::NOT_SIGNALED);
8480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    ResponseCallback callback =
8580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn        base::Bind(&AssignAndSignal, &response, &response_ready);
8680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    // Use SendCommandTask instead of binding to next_transceiver_ directly to
8780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    // leverage weak pointer semantics.
884dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn    base::Closure task =
894dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        base::Bind(&BackgroundCommandTransceiver::SendCommandTask, GetWeakPtr(),
904dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                   command, callback);
9180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    task_runner_->PostNonNestableTask(FROM_HERE, task);
9280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    response_ready.Wait();
9380c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    return response;
9480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  } else {
9580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    return next_transceiver_->SendCommandAndWait(command);
9680c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  }
9780c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}
9880c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
9980c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahnvoid BackgroundCommandTransceiver::SendCommandTask(
10080c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const std::string& command,
10180c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn    const ResponseCallback& callback) {
10280c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn  next_transceiver_->SendCommand(command, callback);
10380c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}
10480c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn
10580c739e10fd606b24e2656cad6e566c66bb218d4Darren Krahn}  // namespace trunks
106