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