root/tools/android/forwarder2/host_controller.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. Create
  2. Start
  3. thread_
  4. ReadNextCommandSoon
  5. ReadCommandOnInternalThread
  6. StartForwarder
  7. OnInternalThreadError
  8. UnmapPortOnDevice

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "tools/android/forwarder2/host_controller.h"

#include <string>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "tools/android/forwarder2/command.h"
#include "tools/android/forwarder2/forwarder.h"
#include "tools/android/forwarder2/socket.h"

namespace forwarder2 {

// static
scoped_ptr<HostController> HostController::Create(
    int device_port,
    int host_port,
    int adb_port,
    int exit_notifier_fd,
    const ErrorCallback& error_callback) {
  scoped_ptr<HostController> host_controller;
  scoped_ptr<PipeNotifier> delete_controller_notifier(new PipeNotifier());
  scoped_ptr<Socket> adb_control_socket(new Socket());
  adb_control_socket->AddEventFd(exit_notifier_fd);
  adb_control_socket->AddEventFd(delete_controller_notifier->receiver_fd());
  if (!adb_control_socket->ConnectTcp(std::string(), adb_port)) {
    LOG(ERROR) << "Could not connect HostController socket on port: "
               << adb_port;
    return host_controller.Pass();
  }
  // Send the command to the device start listening to the "device_forward_port"
  bool send_command_success = SendCommand(
      command::LISTEN, device_port, adb_control_socket.get());
  CHECK(send_command_success);
  int device_port_allocated;
  command::Type command;
  if (!ReadCommand(
          adb_control_socket.get(), &device_port_allocated, &command) ||
      command != command::BIND_SUCCESS) {
    LOG(ERROR) << "Device binding error using port " << device_port;
    return host_controller.Pass();
  }
  host_controller.reset(
      new HostController(
          device_port_allocated, host_port, adb_port, exit_notifier_fd,
          error_callback, adb_control_socket.Pass(),
          delete_controller_notifier.Pass()));
  return host_controller.Pass();
}

HostController::~HostController() {
  DCHECK(deletion_task_runner_->RunsTasksOnCurrentThread());
  delete_controller_notifier_->Notify();
}

void HostController::Start() {
  thread_.Start();
  ReadNextCommandSoon();
}

HostController::HostController(
    int device_port,
    int host_port,
    int adb_port,
    int exit_notifier_fd,
    const ErrorCallback& error_callback,
    scoped_ptr<Socket> adb_control_socket,
    scoped_ptr<PipeNotifier> delete_controller_notifier)
    : self_deleter_helper_(this, error_callback),
      device_port_(device_port),
      host_port_(host_port),
      adb_port_(adb_port),
      global_exit_notifier_fd_(exit_notifier_fd),
      adb_control_socket_(adb_control_socket.Pass()),
      delete_controller_notifier_(delete_controller_notifier.Pass()),
      deletion_task_runner_(base::MessageLoopProxy::current()),
      thread_("HostControllerThread") {
}

void HostController::ReadNextCommandSoon() {
  thread_.message_loop_proxy()->PostTask(
      FROM_HERE,
      base::Bind(&HostController::ReadCommandOnInternalThread,
                 base::Unretained(this)));
}

void HostController::ReadCommandOnInternalThread() {
  if (!ReceivedCommand(command::ACCEPT_SUCCESS, adb_control_socket_.get())) {
    LOG(ERROR) << "Did not receive ACCEPT_SUCCESS for port: "
               << host_port_;
    OnInternalThreadError();
    return;
  }
  // Try to connect to host server.
  scoped_ptr<Socket> host_server_data_socket(new Socket());
  if (!host_server_data_socket->ConnectTcp(std::string(), host_port_)) {
    LOG(ERROR) << "Could not Connect HostServerData socket on port: "
               << host_port_;
    SendCommand(
        command::HOST_SERVER_ERROR, device_port_, adb_control_socket_.get());
    if (ReceivedCommand(command::ACK, adb_control_socket_.get())) {
      // It can continue if the host forwarder could not connect to the host
      // server but the device acknowledged that, so that the device could
      // re-try later.
      ReadNextCommandSoon();
      return;
    }
    OnInternalThreadError();
    return;
  }
  LOG(INFO) << "Will send HOST_SERVER_SUCCESS: " << host_port_;
  SendCommand(
      command::HOST_SERVER_SUCCESS, device_port_, adb_control_socket_.get());
  StartForwarder(host_server_data_socket.Pass());
  ReadNextCommandSoon();
}

void HostController::StartForwarder(
    scoped_ptr<Socket> host_server_data_socket) {
  scoped_ptr<Socket> adb_data_socket(new Socket());
  if (!adb_data_socket->ConnectTcp("", adb_port_)) {
    LOG(ERROR) << "Could not connect AdbDataSocket on port: " << adb_port_;
    OnInternalThreadError();
    return;
  }
  // Open the Adb data connection, and send a command with the
  // |device_forward_port| as a way for the device to identify the connection.
  SendCommand(command::DATA_CONNECTION, device_port_, adb_data_socket.get());

  // Check that the device received the new Adb Data Connection. Note that this
  // check is done through the |adb_control_socket_| that is handled in the
  // DeviceListener thread just after the call to WaitForAdbDataSocket().
  if (!ReceivedCommand(command::ADB_DATA_SOCKET_SUCCESS,
                       adb_control_socket_.get())) {
    LOG(ERROR) << "Device could not handle the new Adb Data Connection.";
    OnInternalThreadError();
    return;
  }
  forwarders_manager_.CreateAndStartNewForwarder(
      host_server_data_socket.Pass(), adb_data_socket.Pass());
}

void HostController::OnInternalThreadError() {
  UnmapPortOnDevice();
  self_deleter_helper_.MaybeSelfDeleteSoon();
}

void HostController::UnmapPortOnDevice() {
  Socket socket;
  if (!socket.ConnectTcp("", adb_port_)) {
    LOG(ERROR) << "Could not connect to device on port " << adb_port_;
    return;
  }
  if (!SendCommand(command::UNLISTEN, device_port_, &socket)) {
    LOG(ERROR) << "Could not send unmap command for port " << device_port_;
    return;
  }
  if (!ReceivedCommand(command::UNLISTEN_SUCCESS, &socket)) {
    LOG(ERROR) << "Unamp command failed for port " << device_port_;
    return;
  }
}

}  // namespace forwarder2

/* [<][>][^][v][top][bottom][index][help] */