Home | History | Annotate | Download | only in forwarder2
      1 // Copyright (c) 2012 The Chromium 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 "tools/android/forwarder2/host_controller.h"
      6 
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "tools/android/forwarder2/command.h"
     14 #include "tools/android/forwarder2/forwarder.h"
     15 #include "tools/android/forwarder2/socket.h"
     16 
     17 namespace forwarder2 {
     18 
     19 // static
     20 scoped_ptr<HostController> HostController::Create(
     21     int device_port,
     22     int host_port,
     23     int adb_port,
     24     int exit_notifier_fd,
     25     const ErrorCallback& error_callback) {
     26   scoped_ptr<HostController> host_controller;
     27   scoped_ptr<PipeNotifier> delete_controller_notifier(new PipeNotifier());
     28   scoped_ptr<Socket> adb_control_socket(new Socket());
     29   adb_control_socket->AddEventFd(exit_notifier_fd);
     30   adb_control_socket->AddEventFd(delete_controller_notifier->receiver_fd());
     31   if (!adb_control_socket->ConnectTcp(std::string(), adb_port)) {
     32     LOG(ERROR) << "Could not connect HostController socket on port: "
     33                << adb_port;
     34     return host_controller.Pass();
     35   }
     36   // Send the command to the device start listening to the "device_forward_port"
     37   bool send_command_success = SendCommand(
     38       command::LISTEN, device_port, adb_control_socket.get());
     39   CHECK(send_command_success);
     40   int device_port_allocated;
     41   command::Type command;
     42   if (!ReadCommand(
     43           adb_control_socket.get(), &device_port_allocated, &command) ||
     44       command != command::BIND_SUCCESS) {
     45     LOG(ERROR) << "Device binding error using port " << device_port;
     46     return host_controller.Pass();
     47   }
     48   host_controller.reset(
     49       new HostController(
     50           device_port_allocated, host_port, adb_port, exit_notifier_fd,
     51           error_callback, adb_control_socket.Pass(),
     52           delete_controller_notifier.Pass()));
     53   return host_controller.Pass();
     54 }
     55 
     56 HostController::~HostController() {
     57   DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
     58   delete_controller_notifier_->Notify();
     59   // Note that the Forwarder instance (that also received a delete notification)
     60   // might still be running on its own thread at this point. This is not a
     61   // problem since it will self-delete once the socket that it is operating on
     62   // is closed.
     63 }
     64 
     65 void HostController::Start() {
     66   thread_.Start();
     67   ReadNextCommandSoon();
     68 }
     69 
     70 HostController::HostController(
     71     int device_port,
     72     int host_port,
     73     int adb_port,
     74     int exit_notifier_fd,
     75     const ErrorCallback& error_callback,
     76     scoped_ptr<Socket> adb_control_socket,
     77     scoped_ptr<PipeNotifier> delete_controller_notifier)
     78     : self_deleter_helper_(this, error_callback),
     79       device_port_(device_port),
     80       host_port_(host_port),
     81       adb_port_(adb_port),
     82       global_exit_notifier_fd_(exit_notifier_fd),
     83       adb_control_socket_(adb_control_socket.Pass()),
     84       delete_controller_notifier_(delete_controller_notifier.Pass()),
     85       deletion_task_runner_(base::MessageLoopProxy::current()),
     86       thread_("HostControllerThread") {
     87 }
     88 
     89 void HostController::ReadNextCommandSoon() {
     90   thread_.message_loop_proxy()->PostTask(
     91       FROM_HERE,
     92       base::Bind(&HostController::ReadCommandOnInternalThread,
     93                  base::Unretained(this)));
     94 }
     95 
     96 void HostController::ReadCommandOnInternalThread() {
     97   if (!ReceivedCommand(command::ACCEPT_SUCCESS, adb_control_socket_.get())) {
     98     LOG(ERROR) << "Did not receive ACCEPT_SUCCESS for port: "
     99                << host_port_;
    100     OnInternalThreadError();
    101     return;
    102   }
    103   // Try to connect to host server.
    104   scoped_ptr<Socket> host_server_data_socket(CreateSocket());
    105   if (!host_server_data_socket->ConnectTcp(std::string(), host_port_)) {
    106     LOG(ERROR) << "Could not Connect HostServerData socket on port: "
    107                << host_port_;
    108     SendCommand(
    109         command::HOST_SERVER_ERROR, device_port_, adb_control_socket_.get());
    110     if (ReceivedCommand(command::ACK, adb_control_socket_.get())) {
    111       // It can continue if the host forwarder could not connect to the host
    112       // server but the device acknowledged that, so that the device could
    113       // re-try later.
    114       ReadNextCommandSoon();
    115       return;
    116     }
    117     LOG(ERROR) << "Will delete host controller: " << host_port_;
    118     OnInternalThreadError();
    119     return;
    120   }
    121   LOG(INFO) << "Will send HOST_SERVER_SUCCESS: " << host_port_;
    122   SendCommand(
    123       command::HOST_SERVER_SUCCESS, device_port_, adb_control_socket_.get());
    124   StartForwarder(host_server_data_socket.Pass());
    125   ReadNextCommandSoon();
    126 }
    127 
    128 void HostController::StartForwarder(
    129     scoped_ptr<Socket> host_server_data_socket) {
    130   scoped_ptr<Socket> adb_data_socket(CreateSocket());
    131   if (!adb_data_socket->ConnectTcp("", adb_port_)) {
    132     LOG(ERROR) << "Could not connect AdbDataSocket on port: " << adb_port_;
    133     OnInternalThreadError();
    134     return;
    135   }
    136   // Open the Adb data connection, and send a command with the
    137   // |device_forward_port| as a way for the device to identify the connection.
    138   SendCommand(command::DATA_CONNECTION, device_port_, adb_data_socket.get());
    139 
    140   // Check that the device received the new Adb Data Connection. Note that this
    141   // check is done through the |adb_control_socket_| that is handled in the
    142   // DeviceListener thread just after the call to WaitForAdbDataSocket().
    143   if (!ReceivedCommand(command::ADB_DATA_SOCKET_SUCCESS,
    144                        adb_control_socket_.get())) {
    145     LOG(ERROR) << "Device could not handle the new Adb Data Connection.";
    146     OnInternalThreadError();
    147     return;
    148   }
    149   forwarder2::StartForwarder(
    150       host_server_data_socket.Pass(), adb_data_socket.Pass());
    151 }
    152 
    153 scoped_ptr<Socket> HostController::CreateSocket() {
    154   scoped_ptr<Socket> socket(new Socket());
    155   socket->AddEventFd(global_exit_notifier_fd_);
    156   socket->AddEventFd(delete_controller_notifier_->receiver_fd());
    157   return socket.Pass();
    158 }
    159 
    160 void HostController::OnInternalThreadError() {
    161   UnmapPortOnDevice();
    162   self_deleter_helper_.MaybeSelfDeleteSoon();
    163 }
    164 
    165 void HostController::UnmapPortOnDevice() {
    166   Socket socket;
    167   if (!socket.ConnectTcp("", adb_port_)) {
    168     LOG(ERROR) << "Could not connect to device on port " << adb_port_;
    169     return;
    170   }
    171   if (!SendCommand(command::UNLISTEN, device_port_, &socket)) {
    172     LOG(ERROR) << "Could not send unmap command for port " << device_port_;
    173     return;
    174   }
    175   if (!ReceivedCommand(command::UNLISTEN_SUCCESS, &socket)) {
    176     LOG(ERROR) << "Unamp command failed for port " << device_port_;
    177     return;
    178   }
    179 }
    180 
    181 }  // namespace forwarder2
    182