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