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