Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(439)

Side by Side Diff: tools/android/forwarder2/host_controllers_manager.cc

Issue 2736053003: [Android] Fix port leak in the forwarder. (Closed)
Patch Set: use callback for exit notifier fd Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // 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
13 namespace forwarder2 {
14
15 HostControllersManager::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
22 HostControllersManager::~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
29 void 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 void HostControllersManager::HandleRequestForTesting(
46 const std::string& adb_path,
47 const std::string& device_serial,
48 int command,
49 int device_port,
50 int host_port,
51 std::unique_ptr<Socket> client_socket) {
52 // Lazy initialize so that the CLI process doesn't get this thread created.
53 InitOnce();
54 HandleRequestOnInternalThread(adb_path, device_serial, command, device_port,
55 host_port, std::move(client_socket));
56 }
57
58 // static
59 std::string HostControllersManager::MakeHostControllerMapKey(int adb_port,
60 int device_port) {
61 return base::StringPrintf("%d:%d", adb_port, device_port);
62 }
63
64 void HostControllersManager::InitOnce() {
65 if (thread_.get())
66 return;
67 at_exit_manager_.reset(new base::AtExitManager());
68 thread_.reset(new base::Thread("HostControllersManagerThread"));
69 thread_->Start();
70 }
71
72 // static
73 void HostControllersManager::DeleteHostController(
74 const base::WeakPtr<HostControllersManager>& manager_ptr,
75 std::unique_ptr<HostController> host_controller) {
76 HostController* const controller = host_controller.release();
77 HostControllersManager* const manager = manager_ptr.get();
78 if (!manager) {
79 // Note that |controller| is not leaked in this case since the host
80 // controllers manager owns the controllers. If the manager was deleted
81 // then all the controllers (including |controller|) were also deleted.
82 return;
83 }
84 DCHECK(manager->thread_->task_runner()->RunsTasksOnCurrentThread());
85 // Note that this will delete |controller| which is owned by the map.
86 DeleteRefCountedValueInMap(
87 MakeHostControllerMapKey(controller->adb_port(),
88 controller->device_port()),
89 manager->controllers_.get());
90 }
91
92 void HostControllersManager::Map(const std::string& adb_path,
93 const std::string& device_serial,
94 int adb_port,
95 int device_port,
96 int host_port,
97 Socket* client_socket) {
98 if (host_port < 0) {
99 SendMessage("ERROR: missing host port\n", client_socket);
100 return;
101 }
102 const bool use_dynamic_port_allocation = device_port == 0;
103 if (!use_dynamic_port_allocation) {
104 const std::string controller_key =
105 MakeHostControllerMapKey(adb_port, device_port);
106 if (controllers_->find(controller_key) != controllers_->end()) {
107 LOG(INFO) << "Already forwarding device port " << device_port
108 << " to host port " << host_port;
109 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
110 client_socket);
111 return;
112 }
113 }
114 // Create a new host controller.
115 std::unique_ptr<HostController> host_controller(HostController::Create(
116 device_serial, device_port, host_port, adb_port,
117 exit_notifier_fd_callback_.Run(),
118 base::Bind(&HostControllersManager::DeleteHostController,
119 weak_ptr_factory_.GetWeakPtr())));
120 if (!host_controller.get()) {
121 has_failed_ = true;
122 SendMessage("ERROR: Connection to device failed.\n", client_socket);
123 LogExistingControllers(client_socket);
124 return;
125 }
126 // Get the current allocated port.
127 device_port = host_controller->device_port();
128 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
129 << host_port;
130 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
131 if (!SendMessage(msg, client_socket))
132 return;
133 host_controller->Start();
134 controllers_->insert(
135 std::make_pair(MakeHostControllerMapKey(adb_port, device_port),
136 linked_ptr<HostController>(host_controller.release())));
137 }
138
139 void HostControllersManager::Unmap(const std::string& adb_path,
140 const std::string& device_serial,
141 int adb_port,
142 int device_port,
143 Socket* client_socket) {
144 // Remove the previously created host controller.
145 const std::string controller_key =
146 MakeHostControllerMapKey(adb_port, device_port);
147 const bool controller_did_exist =
148 DeleteRefCountedValueInMap(controller_key, controllers_.get());
149 if (!controller_did_exist) {
150 SendMessage("ERROR: could not unmap port.\n", client_socket);
151 LogExistingControllers(client_socket);
152 } else {
153 SendMessage("OK", client_socket);
154 }
155
156 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
157 }
158
159 void HostControllersManager::UnmapAll(const std::string& adb_path,
160 const std::string& device_serial,
161 int adb_port,
162 Socket* client_socket) {
163 const std::string adb_port_str = base::StringPrintf("%d", adb_port);
164 for (HostControllerMap::const_iterator controller_key =
165 controllers_->cbegin();
166 controller_key != controllers_->cend(); ++controller_key) {
167 std::vector<std::string> pieces =
168 base::SplitString(controller_key->first, ":", base::KEEP_WHITESPACE,
169 base::SPLIT_WANT_ALL);
170 if (pieces.size() == 2) {
171 if (pieces[0] == adb_port_str) {
172 DeleteRefCountedValueInMapFromIterator(controller_key,
173 controllers_.get());
174 }
175 } else {
176 LOG(ERROR) << "Unexpected controller key: " << controller_key->first;
177 }
178 }
179
180 RemoveAdbPortForDeviceIfNeeded(adb_path, device_serial);
181 SendMessage("OK", client_socket);
182 }
183
184 void HostControllersManager::HandleRequestOnInternalThread(
185 const std::string& adb_path,
186 const std::string& device_serial,
187 int command,
188 int device_port,
189 int host_port,
190 std::unique_ptr<Socket> client_socket) {
191 const int adb_port = GetAdbPortForDevice(adb_path, device_serial);
192 if (adb_port < 0) {
193 SendMessage(
194 "ERROR: could not get adb port for device. You might need to add "
195 "'adb' to your PATH or provide the device serial id.\n",
196 client_socket.get());
197 return;
198 }
199 switch (command) {
200 case MAP:
201 Map(adb_path, device_serial, adb_port, device_port, host_port,
202 client_socket.get());
203 break;
204 case UNMAP:
205 Unmap(adb_path, device_serial, adb_port, device_port,
206 client_socket.get());
207 break;
208 case UNMAP_ALL:
209 UnmapAll(adb_path, device_serial, adb_port, client_socket.get());
210 break;
211 default:
212 SendMessage(
213 base::StringPrintf("ERROR: unrecognized command %d\n", command),
214 client_socket.get());
215 break;
216 }
217 }
218
219 void HostControllersManager::LogExistingControllers(Socket* client_socket) {
220 SendMessage("ERROR: Existing controllers:\n", client_socket);
221 for (const auto& controller : *controllers_) {
222 SendMessage(base::StringPrintf("ERROR: %s\n", controller.first.c_str()),
223 client_socket);
224 }
225 }
226
227 bool HostControllersManager::Adb(const std::string& adb_path,
228 const std::string& device_serial,
229 const std::string& command,
230 std::string* output_and_error) {
231 // We use the vector version of GetAppOutputAndError rather than the
232 // more standard base::CommandLine version because base::CommandLine
233 // reorders the command s.t. switches precede arguments and doing so
234 // here creates an invalid adb command.
235 std::vector<std::string> adb_command{adb_path};
236 if (!device_serial.empty()) {
237 adb_command.push_back("-s");
238 adb_command.push_back(device_serial);
239 }
240 const std::vector<std::string> split_command = base::SplitString(
241 command, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
242 adb_command.insert(adb_command.end(), split_command.begin(),
243 split_command.end());
244 return GetAppOutputAndError(adb_command, output_and_error);
245 }
246
247 void HostControllersManager::RemoveAdbPortForDeviceIfNeeded(
248 const std::string& adb_path,
249 const std::string& device_serial) {
250 base::hash_map<std::string, int>::const_iterator it =
251 device_serial_to_adb_port_map_.find(device_serial);
252 if (it == device_serial_to_adb_port_map_.end())
253 return;
254
255 int port = it->second;
256 const std::string prefix = base::StringPrintf("%d:", port);
257 for (HostControllerMap::const_iterator others = controllers_->begin();
258 others != controllers_->end(); ++others) {
259 if (base::StartsWith(others->first, prefix, base::CompareCase::SENSITIVE))
260 return;
261 }
262 // No other port is being forwarded to this device:
263 // - Remove it from our internal serial -> adb port map.
264 // - Remove from "adb forward" command.
265 LOG(INFO) << "Device " << device_serial << " has no more ports.";
266 device_serial_to_adb_port_map_.erase(device_serial);
267 const std::string command =
268 base::StringPrintf("forward --remove tcp:%d", port);
269 std::string output;
270 if (!Adb(adb_path, device_serial, command, &output)) {
271 LOG(ERROR) << command << " failed. output: \"" << output << "\"";
272 } else {
273 LOG(INFO) << command << " (output: \"" << output << "\")";
274 }
275 // Wait for the socket to be fully unmapped.
276 const std::string port_mapped_cmd = base::StringPrintf("lsof -nPi:%d", port);
277 const std::vector<std::string> port_mapped_split_cmd = base::SplitString(
278 port_mapped_cmd, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
279 const int poll_interval_us = 500 * 1000;
280 int retries = 3;
281 while (retries) {
282 // lsof failure means the port was successfully unmapped.
283 bool port_unmapped = !GetAppOutputAndError(port_mapped_split_cmd, &output);
284 LOG(INFO) << "Device " << device_serial << " port " << port
285 << (port_unmapped ? "" : " not") << " unmapped";
286 if (port_unmapped)
287 break;
288 --retries;
289 usleep(poll_interval_us);
290 }
291 }
292
293 void HostControllersManager::SetAdbPortForDeviceForTesting(
294 const std::string& serial,
295 int adb_port) {
296 device_serial_to_adb_port_map_[serial] = adb_port;
297 }
298
299 int HostControllersManager::GetAdbPortForDevice(
300 const std::string adb_path,
301 const std::string& device_serial) {
302 base::hash_map<std::string, int>::const_iterator it =
303 device_serial_to_adb_port_map_.find(device_serial);
304 if (it != device_serial_to_adb_port_map_.end())
305 return it->second;
306 Socket bind_socket;
307 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
308 const int port = bind_socket.GetPort();
309 bind_socket.Close();
310 const std::string command = base::StringPrintf(
311 "forward tcp:%d localabstract:chrome_device_forwarder", port);
312 std::string output;
313 if (!Adb(adb_path, device_serial, command, &output)) {
314 LOG(ERROR) << command << " failed. output: " << output;
315 return -1;
316 }
317 LOG(INFO) << command;
318 device_serial_to_adb_port_map_[device_serial] = port;
319 return port;
320 }
321
322 bool HostControllersManager::SendMessage(const std::string& msg,
323 Socket* client_socket) {
324 bool result = client_socket->WriteString(msg);
325 DCHECK(result);
326 if (!result)
327 has_failed_ = true;
328 return result;
329 }
330
331 bool HostControllersManager::GetAppOutputAndError(
332 const std::vector<std::string>& argv,
333 std::string* output) {
334 return base::GetAppOutputAndError(argv, output);
335 }
336
337 } // namespace forwarder2
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698