[go: nahoru, domu]

blob: 2b3428a288c8f04f0ab761d5653ac8323e3b238c [file] [log] [blame]
jbudorick86c756c2017-03-29 17:33:541// Copyright 2017 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_controllers_manager.h"
6
7#include "base/process/launch.h"
8#include "base/strings/string_split.h"
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "tools/android/forwarder2/util.h"
12
13namespace forwarder2 {
14
15HostControllersManager::HostControllersManager(
16 base::Callback<int()> exit_notifier_fd_callback)
17 : controllers_(new HostControllerMap()),
18 exit_notifier_fd_callback_(exit_notifier_fd_callback),
19 has_failed_(false),
20 weak_ptr_factory_(this) {}
21
22HostControllersManager::~HostControllersManager() {
23 if (!thread_.get())
24 return;
25 // Delete the controllers on the thread they were created on.
26 thread_->task_runner()->DeleteSoon(FROM_HERE, controllers_.release());
27}
28
29void HostControllersManager::HandleRequest(
30 const std::string& adb_path,
31 const std::string& device_serial,
32 int command,
33 int device_port,
34 int host_port,
35 std::unique_ptr<Socket> client_socket) {
36 // Lazy initialize so that the CLI process doesn't get this thread created.
37 InitOnce();
38 thread_->task_runner()->PostTask(
39 FROM_HERE,
40 base::Bind(&HostControllersManager::HandleRequestOnInternalThread,
41 base::Unretained(this), adb_path, device_serial, command,
42 device_port, host_port, base::Passed(&client_socket)));
43}
44
45// static
46std::string HostControllersManager::MakeHostControllerMapKey(int adb_port,
47 int device_port) {
48 return base::StringPrintf("%d:%d", adb_port, device_port);
49}
50
51void HostControllersManager::InitOnce() {
52 if (thread_.get())
53 return;
54 at_exit_manager_.reset(new base::AtExitManager());
55 thread_.reset(new base::Thread("HostControllersManagerThread"));
56 thread_->Start();
57}
58
59// static
60void HostControllersManager::DeleteHostController(
61 const base::WeakPtr<HostControllersManager>& manager_ptr,
62 std::unique_ptr<HostController> host_controller) {
63 HostController* const controller = host_controller.release();
64 HostControllersManager* const manager = manager_ptr.get();
65 if (!manager) {
66 // Note that |controller| is not leaked in this case since the host
67 // controllers manager owns the controllers. If the manager was deleted
68 // then all the controllers (including |controller|) were also deleted.
69 return;
70 }
peary23808747e2017-05-18 03:40:4071 DCHECK(manager->thread_->task_runner()->RunsTasksInCurrentSequence());
jbudorick86c756c2017-03-29 17:33:5472 // Note that this will delete |controller| which is owned by the map.
73 DeleteRefCountedValueInMap(
74 MakeHostControllerMapKey(controller->adb_port(),
75 controller->device_port()),
76 manager->controllers_.get());
77}
78
79void HostControllersManager::Map(const std::string& adb_path,
80 const std::string& device_serial,
81 int adb_port,
82 int device_port,
83 int host_port,
84 Socket* client_socket) {
85 if (host_port < 0) {
86 SendMessage("ERROR: missing host port\n", client_socket);
87 return;
88 }
89 const bool use_dynamic_port_allocation = device_port == 0;
90 if (!use_dynamic_port_allocation) {
91 const std::string controller_key =
92 MakeHostControllerMapKey(adb_port, device_port);
93 if (controllers_->find(controller_key) != controllers_->end()) {
94 LOG(INFO) << "Already forwarding device port " << device_port
95 << " to host port " << host_port;
96 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
97 client_socket);
98 return;
99 }
100 }
101 // Create a new host controller.
102 std::unique_ptr<HostController> host_controller(HostController::Create(
103 device_serial, device_port, host_port, adb_port,
104 exit_notifier_fd_callback_.Run(),
105 base::Bind(&HostControllersManager::DeleteHostController,
106 weak_ptr_factory_.GetWeakPtr())));
107 if (!host_controller.get()) {
108 has_failed_ = true;
109 SendMessage("ERROR: Connection to device failed.\n", client_socket);
110 LogExistingControllers(client_socket);
111 return;
112 }
113 // Get the current allocated port.
114 device_port = host_controller->device_port();
115 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
116 << host_port;
117 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
118 if (!SendMessage(msg, client_socket))
119 return;
120 host_controller->Start();
Avi Drissmanddb92bd2018-12-17 19:04:43121 controllers_->emplace(MakeHostControllerMapKey(adb_port, device_port),
122 std::move(host_controller));
jbudorick86c756c2017-03-29 17:33:54123}
124
125void HostControllersManager::Unmap(const std::string& adb_path,
126 const std::string& device_serial,
127 int adb_port,
128 int device_port,
129 Socket* client_socket) {
130 // Remove the previously created host controller.
131 const std::string controller_key =
132 MakeHostControllerMapKey(adb_port, device_port);
133 const bool controller_did_exist =
134 DeleteRefCountedValueInMap(controller_key, controllers_.get());
135 if (!controller_did_exist) {
136 SendMessage("ERROR: could not unmap port.\n", client_socket);
137 LogExistingControllers(client_socket);
138 } else {
139 SendMessage("OK", client_socket);
140 }
141
142 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
143}
144
145void HostControllersManager::UnmapAll(const std::string& adb_path,
146 const std::string& device_serial,
147 int adb_port,
148 Socket* client_socket) {
149 const std::string adb_port_str = base::StringPrintf("%d", adb_port);
Avi Drissmanddb92bd2018-12-17 19:04:43150 for (auto controller_key = controllers_->begin();
151 controller_key != controllers_->end(); ++controller_key) {
jbudorick86c756c2017-03-29 17:33:54152 std::vector<std::string> pieces =
153 base::SplitString(controller_key->first, ":", base::KEEP_WHITESPACE,
154 base::SPLIT_WANT_ALL);
155 if (pieces.size() == 2) {
156 if (pieces[0] == adb_port_str) {
157 DeleteRefCountedValueInMapFromIterator(controller_key,
158 controllers_.get());
159 }
160 } else {
161 LOG(ERROR) << "Unexpected controller key: " << controller_key->first;
162 }
163 }
164
165 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
166 SendMessage("OK", client_socket);
167}
168
169void HostControllersManager::HandleRequestOnInternalThread(
170 const std::string& adb_path,
171 const std::string& device_serial,
172 int command,
173 int device_port,
174 int host_port,
175 std::unique_ptr<Socket> client_socket) {
176 const int adb_port = GetAdbPortForDevice(adb_path, device_serial);
177 if (adb_port < 0) {
178 SendMessage(
179 "ERROR: could not get adb port for device. You might need to add "
180 "'adb' to your PATH or provide the device serial id.\n",
181 client_socket.get());
182 return;
183 }
184 switch (command) {
185 case MAP:
186 Map(adb_path, device_serial, adb_port, device_port, host_port,
187 client_socket.get());
188 break;
189 case UNMAP:
190 Unmap(adb_path, device_serial, adb_port, device_port,
191 client_socket.get());
192 break;
193 case UNMAP_ALL:
194 UnmapAll(adb_path, device_serial, adb_port, client_socket.get());
195 break;
196 default:
197 SendMessage(
198 base::StringPrintf("ERROR: unrecognized command %d\n", command),
199 client_socket.get());
200 break;
201 }
202}
203
204void HostControllersManager::LogExistingControllers(Socket* client_socket) {
205 SendMessage("ERROR: Existing controllers:\n", client_socket);
206 for (const auto& controller : *controllers_) {
207 SendMessage(base::StringPrintf("ERROR: %s\n", controller.first.c_str()),
208 client_socket);
209 }
210}
211
212bool HostControllersManager::Adb(const std::string& adb_path,
213 const std::string& device_serial,
214 const std::string& command,
215 std::string* output_and_error) {
216 // We use the vector version of GetAppOutputAndError rather than the
217 // more standard base::CommandLine version because base::CommandLine
218 // reorders the command s.t. switches precede arguments and doing so
219 // here creates an invalid adb command.
220 std::vector<std::string> adb_command{adb_path};
221 if (!device_serial.empty()) {
222 adb_command.push_back("-s");
223 adb_command.push_back(device_serial);
224 }
225 const std::vector<std::string> split_command = base::SplitString(
226 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
227 adb_command.insert(adb_command.end(), split_command.begin(),
228 split_command.end());
229 return GetAppOutputAndError(adb_command, output_and_error);
230}
231
232void HostControllersManager::RemoveAdbPortForDeviceIfNeeded(
233 const std::string& adb_path,
234 const std::string& device_serial) {
Takuto Ikutaadf31eb2019-01-05 00:32:48235 std::unordered_map<std::string, int>::const_iterator it =
jbudorick86c756c2017-03-29 17:33:54236 device_serial_to_adb_port_map_.find(device_serial);
237 if (it == device_serial_to_adb_port_map_.end())
238 return;
239
240 int port = it->second;
241 const std::string prefix = base::StringPrintf("%d:", port);
Avi Drissmanddb92bd2018-12-17 19:04:43242 for (auto others = controllers_->begin(); others != controllers_->end();
243 ++others) {
jbudorick86c756c2017-03-29 17:33:54244 if (base::StartsWith(others->first, prefix, base::CompareCase::SENSITIVE))
245 return;
246 }
247 // No other port is being forwarded to this device:
248 // - Remove it from our internal serial -> adb port map.
249 // - Remove from "adb forward" command.
250 LOG(INFO) << "Device " << device_serial << " has no more ports.";
251 device_serial_to_adb_port_map_.erase(device_serial);
252 const std::string command =
253 base::StringPrintf("forward --remove tcp:%d", port);
254 std::string output;
255 if (!Adb(adb_path, device_serial, command, &output)) {
256 LOG(ERROR) << command << " failed. output: \"" << output << "\"";
257 } else {
258 LOG(INFO) << command << " (output: \"" << output << "\")";
259 }
260 // Wait for the socket to be fully unmapped.
261 const std::string port_mapped_cmd = base::StringPrintf("lsof -nPi:%d", port);
262 const std::vector<std::string> port_mapped_split_cmd = base::SplitString(
263 port_mapped_cmd, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
264 const int poll_interval_us = 500 * 1000;
265 int retries = 3;
266 while (retries) {
267 // lsof failure means the port was successfully unmapped.
268 bool port_unmapped = !GetAppOutputAndError(port_mapped_split_cmd, &output);
269 LOG(INFO) << "Device " << device_serial << " port " << port
270 << (port_unmapped ? "" : " not") << " unmapped";
271 if (port_unmapped)
272 break;
273 --retries;
274 usleep(poll_interval_us);
275 }
276}
277
278int HostControllersManager::GetAdbPortForDevice(
279 const std::string adb_path,
280 const std::string& device_serial) {
Takuto Ikutaadf31eb2019-01-05 00:32:48281 std::unordered_map<std::string, int>::const_iterator it =
jbudorick86c756c2017-03-29 17:33:54282 device_serial_to_adb_port_map_.find(device_serial);
283 if (it != device_serial_to_adb_port_map_.end())
284 return it->second;
285 Socket bind_socket;
286 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
287 const int port = bind_socket.GetPort();
288 bind_socket.Close();
289 const std::string command = base::StringPrintf(
290 "forward tcp:%d localabstract:chrome_device_forwarder", port);
291 std::string output;
292 if (!Adb(adb_path, device_serial, command, &output)) {
293 LOG(ERROR) << command << " failed. output: " << output;
294 return -1;
295 }
296 LOG(INFO) << command;
297 device_serial_to_adb_port_map_[device_serial] = port;
298 return port;
299}
300
301bool HostControllersManager::SendMessage(const std::string& msg,
302 Socket* client_socket) {
303 bool result = client_socket->WriteString(msg);
304 DCHECK(result);
305 if (!result)
306 has_failed_ = true;
307 return result;
308}
309
310bool HostControllersManager::GetAppOutputAndError(
311 const std::vector<std::string>& argv,
312 std::string* output) {
313 return base::GetAppOutputAndError(argv, output);
314}
315
316} // namespace forwarder2