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.
5 #include "tools/android/forwarder2/host_controller.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"
17 namespace forwarder2 {
20 scoped_ptr<HostController> HostController::Create(
25 const DeletionCallback& deletion_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: "
34 return host_controller.Pass();
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;
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();
48 host_controller.reset(
50 device_port_allocated, host_port, adb_port, exit_notifier_fd,
51 deletion_callback, adb_control_socket.Pass(),
52 delete_controller_notifier.Pass()));
53 return host_controller.Pass();
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
65 void HostController::Start() {
67 ReadNextCommandSoon();
70 HostController::HostController(
75 const DeletionCallback& deletion_callback,
76 scoped_ptr<Socket> adb_control_socket,
77 scoped_ptr<PipeNotifier> delete_controller_notifier)
78 : device_port_(device_port),
79 host_port_(host_port),
81 global_exit_notifier_fd_(exit_notifier_fd),
82 deletion_callback_(deletion_callback),
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") {
89 void HostController::ReadNextCommandSoon() {
90 thread_.message_loop_proxy()->PostTask(
92 base::Bind(&HostController::ReadCommandOnInternalThread,
93 base::Unretained(this)));
96 void HostController::ReadCommandOnInternalThread() {
97 if (!ReceivedCommand(command::ACCEPT_SUCCESS, adb_control_socket_.get())) {
101 // Try to connect to host server.
102 scoped_ptr<Socket> host_server_data_socket(CreateSocket());
103 if (!host_server_data_socket->ConnectTcp(std::string(), host_port_)) {
104 LOG(ERROR) << "Could not Connect HostServerData socket on port: "
107 command::HOST_SERVER_ERROR, device_port_, adb_control_socket_.get());
108 if (ReceivedCommand(command::ACK, adb_control_socket_.get())) {
109 // It can continue if the host forwarder could not connect to the host
110 // server but the device acknowledged that, so that the device could
112 ReadNextCommandSoon();
119 command::HOST_SERVER_SUCCESS, device_port_, adb_control_socket_.get());
120 StartForwarder(host_server_data_socket.Pass());
121 ReadNextCommandSoon();
124 void HostController::StartForwarder(
125 scoped_ptr<Socket> host_server_data_socket) {
126 scoped_ptr<Socket> adb_data_socket(CreateSocket());
127 if (!adb_data_socket->ConnectTcp("", adb_port_)) {
128 LOG(ERROR) << "Could not connect AdbDataSocket on port: " << adb_port_;
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());
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.";
145 forwarder2::StartForwarder(
146 host_server_data_socket.Pass(), adb_data_socket.Pass());
149 scoped_ptr<Socket> HostController::CreateSocket() {
150 scoped_ptr<Socket> socket(new Socket());
151 socket->AddEventFd(global_exit_notifier_fd_);
152 socket->AddEventFd(delete_controller_notifier_->receiver_fd());
153 return socket.Pass();
156 void HostController::SelfDelete() {
157 scoped_ptr<HostController> self_deleter(this);
158 deletion_task_runner_->PostTask(
160 base::Bind(&HostController::SelfDeleteOnDeletionTaskRunner,
161 deletion_callback_, base::Passed(&self_deleter)));
162 // Tell the device to delete its corresponding controller instance before we
165 if (!socket.ConnectTcp("", adb_port_)) {
166 LOG(ERROR) << "Could not connect to device on port " << adb_port_;
169 if (!SendCommand(command::UNLISTEN, device_port_, &socket)) {
170 LOG(ERROR) << "Could not send unmap command for port " << device_port_;
173 if (!ReceivedCommand(command::UNLISTEN_SUCCESS, &socket)) {
174 LOG(ERROR) << "Unamp command failed for port " << device_port_;
180 void HostController::SelfDeleteOnDeletionTaskRunner(
181 const DeletionCallback& deletion_callback,
182 scoped_ptr<HostController> controller) {
183 deletion_callback.Run(controller.Pass());
186 } // namespace forwarder2