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.
18 #include "base/at_exit.h"
19 #include "base/basictypes.h"
20 #include "base/bind.h"
21 #include "base/command_line.h"
22 #include "base/compiler_specific.h"
23 #include "base/containers/hash_tables.h"
24 #include "base/files/file_path.h"
25 #include "base/files/file_util.h"
26 #include "base/logging.h"
27 #include "base/memory/linked_ptr.h"
28 #include "base/memory/scoped_vector.h"
29 #include "base/memory/weak_ptr.h"
30 #include "base/pickle.h"
31 #include "base/safe_strerror_posix.h"
32 #include "base/strings/string_number_conversions.h"
33 #include "base/strings/string_piece.h"
34 #include "base/strings/string_split.h"
35 #include "base/strings/string_util.h"
36 #include "base/strings/stringprintf.h"
37 #include "base/task_runner.h"
38 #include "base/threading/thread.h"
39 #include "tools/android/forwarder2/common.h"
40 #include "tools/android/forwarder2/daemon.h"
41 #include "tools/android/forwarder2/host_controller.h"
42 #include "tools/android/forwarder2/pipe_notifier.h"
43 #include "tools/android/forwarder2/socket.h"
44 #include "tools/android/forwarder2/util.h"
46 namespace forwarder2 {
49 const char kLogFilePath[] = "/tmp/host_forwarder_log";
50 const char kDaemonIdentifier[] = "chrome_host_forwarder_daemon";
52 const int kBufSize = 256;
54 // Needs to be global to be able to be accessed from the signal handler.
55 PipeNotifier* g_notifier = NULL;
57 // Lets the daemon fetch the exit notifier file descriptor.
58 int GetExitNotifierFD() {
60 return g_notifier->receiver_fd();
63 void KillHandler(int signal_number) {
65 if (signal_number != SIGTERM && signal_number != SIGINT) {
66 snprintf(buf, sizeof(buf), "Ignoring unexpected signal %d.", signal_number);
67 SIGNAL_SAFE_LOG(WARNING, buf);
70 snprintf(buf, sizeof(buf), "Received signal %d.", signal_number);
71 SIGNAL_SAFE_LOG(WARNING, buf);
72 static int s_kill_handler_count = 0;
74 // If for some reason the forwarder get stuck in any socket waiting forever,
75 // we can send a SIGKILL or SIGINT three times to force it die
76 // (non-nicely). This is useful when debugging.
77 ++s_kill_handler_count;
78 if (!g_notifier->Notify() || s_kill_handler_count > 2)
82 // Manages HostController instances. There is one HostController instance for
83 // each connection being forwarded. Note that forwarding can happen with many
84 // devices (identified with a serial id).
85 class HostControllersManager {
87 HostControllersManager()
88 : weak_ptr_factory_(this),
89 controllers_(new HostControllerMap()),
93 ~HostControllersManager() {
96 // Delete the controllers on the thread they were created on.
97 thread_->message_loop_proxy()->DeleteSoon(
98 FROM_HERE, controllers_.release());
101 void HandleRequest(const std::string& device_serial,
104 scoped_ptr<Socket> client_socket) {
105 // Lazy initialize so that the CLI process doesn't get this thread created.
107 thread_->message_loop_proxy()->PostTask(
110 &HostControllersManager::HandleRequestOnInternalThread,
111 base::Unretained(this), device_serial, device_port, host_port,
112 base::Passed(&client_socket)));
115 bool has_failed() const { return has_failed_; }
118 typedef base::hash_map<
119 std::string, linked_ptr<HostController> > HostControllerMap;
121 static std::string MakeHostControllerMapKey(int adb_port, int device_port) {
122 return base::StringPrintf("%d:%d", adb_port, device_port);
128 at_exit_manager_.reset(new base::AtExitManager());
129 thread_.reset(new base::Thread("HostControllersManagerThread"));
133 // Invoked when a HostController instance reports an error (e.g. due to a
134 // device connectivity issue). Note that this could be called after the
135 // controller manager was destroyed which is why a weak pointer is used.
136 static void DeleteHostController(
137 const base::WeakPtr<HostControllersManager>& manager_ptr,
138 scoped_ptr<HostController> host_controller) {
139 HostController* const controller = host_controller.release();
140 HostControllersManager* const manager = manager_ptr.get();
142 // Note that |controller| is not leaked in this case since the host
143 // controllers manager owns the controllers. If the manager was deleted
144 // then all the controllers (including |controller|) were also deleted.
147 DCHECK(manager->thread_->message_loop_proxy()->RunsTasksOnCurrentThread());
148 // Note that this will delete |controller| which is owned by the map.
149 DeleteRefCountedValueInMap(
150 MakeHostControllerMapKey(
151 controller->adb_port(), controller->device_port()),
152 manager->controllers_.get());
155 void HandleRequestOnInternalThread(const std::string& device_serial,
158 scoped_ptr<Socket> client_socket) {
159 const int adb_port = GetAdbPortForDevice(device_serial);
162 "ERROR: could not get adb port for device. You might need to add "
163 "'adb' to your PATH or provide the device serial id.",
164 client_socket.get());
167 if (device_port < 0) {
168 // Remove the previously created host controller.
169 const std::string controller_key = MakeHostControllerMapKey(
170 adb_port, -device_port);
171 const bool controller_did_exist = DeleteRefCountedValueInMap(
172 controller_key, controllers_.get());
174 !controller_did_exist ? "ERROR: could not unmap port" : "OK",
175 client_socket.get());
177 RemoveAdbPortForDeviceIfNeeded(device_serial);
181 SendMessage("ERROR: missing host port", client_socket.get());
184 const bool use_dynamic_port_allocation = device_port == 0;
185 if (!use_dynamic_port_allocation) {
186 const std::string controller_key = MakeHostControllerMapKey(
187 adb_port, device_port);
188 if (controllers_->find(controller_key) != controllers_->end()) {
189 LOG(INFO) << "Already forwarding device port " << device_port
190 << " to host port " << host_port;
191 SendMessage(base::StringPrintf("%d:%d", device_port, host_port),
192 client_socket.get());
196 // Create a new host controller.
197 scoped_ptr<HostController> host_controller(
198 HostController::Create(
199 device_port, host_port, adb_port, GetExitNotifierFD(),
200 base::Bind(&HostControllersManager::DeleteHostController,
201 weak_ptr_factory_.GetWeakPtr())));
202 if (!host_controller.get()) {
204 SendMessage("ERROR: Connection to device failed.", client_socket.get());
207 // Get the current allocated port.
208 device_port = host_controller->device_port();
209 LOG(INFO) << "Forwarding device port " << device_port << " to host port "
211 const std::string msg = base::StringPrintf("%d:%d", device_port, host_port);
212 if (!SendMessage(msg, client_socket.get()))
214 host_controller->Start();
215 controllers_->insert(
216 std::make_pair(MakeHostControllerMapKey(adb_port, device_port),
217 linked_ptr<HostController>(host_controller.release())));
220 void RemoveAdbPortForDeviceIfNeeded(const std::string& device_serial) {
221 base::hash_map<std::string, int>::const_iterator it =
222 device_serial_to_adb_port_map_.find(device_serial);
223 if (it == device_serial_to_adb_port_map_.end())
226 int port = it->second;
227 const std::string prefix = base::StringPrintf("%d:", port);
228 for (HostControllerMap::const_iterator others = controllers_->begin();
229 others != controllers_->end(); ++others) {
230 if (others->first.find(prefix) == 0U)
233 // No other port is being forwarded to this device:
234 // - Remove it from our internal serial -> adb port map.
235 // - Remove from "adb forward" command.
236 LOG(INFO) << "Device " << device_serial << " has no more ports.";
237 device_serial_to_adb_port_map_.erase(device_serial);
238 const std::string serial_part = device_serial.empty() ?
239 std::string() : std::string("-s ") + device_serial;
240 const std::string command = base::StringPrintf(
241 "adb %s forward --remove tcp:%d",
244 const int ret = system(command.c_str());
245 LOG(INFO) << command << " ret: " << ret;
246 // Wait for the socket to be fully unmapped.
247 const std::string port_mapped_cmd = base::StringPrintf(
250 const int poll_interval_us = 500 * 1000;
253 const int port_unmapped = system(port_mapped_cmd.c_str());
254 LOG(INFO) << "Device " << device_serial << " port " << port << " unmap "
259 usleep(poll_interval_us);
263 int GetAdbPortForDevice(const std::string& device_serial) {
264 base::hash_map<std::string, int>::const_iterator it =
265 device_serial_to_adb_port_map_.find(device_serial);
266 if (it != device_serial_to_adb_port_map_.end())
269 CHECK(bind_socket.BindTcp("127.0.0.1", 0));
270 const int port = bind_socket.GetPort();
272 const std::string serial_part = device_serial.empty() ?
273 std::string() : std::string("-s ") + device_serial;
274 const std::string command = base::StringPrintf(
275 "adb %s forward tcp:%d localabstract:chrome_device_forwarder",
278 LOG(INFO) << command;
279 const int ret = system(command.c_str());
280 if (ret < 0 || !WIFEXITED(ret) || WEXITSTATUS(ret) != 0)
282 device_serial_to_adb_port_map_[device_serial] = port;
286 bool SendMessage(const std::string& msg, Socket* client_socket) {
287 bool result = client_socket->WriteString(msg);
294 base::WeakPtrFactory<HostControllersManager> weak_ptr_factory_;
295 base::hash_map<std::string, int> device_serial_to_adb_port_map_;
296 scoped_ptr<HostControllerMap> controllers_;
298 scoped_ptr<base::AtExitManager> at_exit_manager_; // Needed by base::Thread.
299 scoped_ptr<base::Thread> thread_;
302 class ServerDelegate : public Daemon::ServerDelegate {
304 ServerDelegate() : has_failed_(false) {}
306 bool has_failed() const {
307 return has_failed_ || controllers_manager_.has_failed();
310 // Daemon::ServerDelegate:
311 virtual void Init() override {
312 LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
314 g_notifier = new PipeNotifier();
315 signal(SIGTERM, KillHandler);
316 signal(SIGINT, KillHandler);
319 virtual void OnClientConnected(scoped_ptr<Socket> client_socket) override {
321 const int bytes_read = client_socket->Read(buf, sizeof(buf));
322 if (bytes_read <= 0) {
323 if (client_socket->DidReceiveEvent())
329 const Pickle command_pickle(buf, bytes_read);
330 PickleIterator pickle_it(command_pickle);
331 std::string device_serial;
332 CHECK(pickle_it.ReadString(&device_serial));
334 if (!pickle_it.ReadInt(&device_port)) {
335 client_socket->WriteString("ERROR: missing device port");
339 if (!pickle_it.ReadInt(&host_port))
341 controllers_manager_.HandleRequest(
342 device_serial, device_port, host_port, client_socket.Pass());
347 HostControllersManager controllers_manager_;
349 DISALLOW_COPY_AND_ASSIGN(ServerDelegate);
352 class ClientDelegate : public Daemon::ClientDelegate {
354 ClientDelegate(const Pickle& command_pickle)
355 : command_pickle_(command_pickle),
359 bool has_failed() const { return has_failed_; }
361 // Daemon::ClientDelegate:
362 virtual void OnDaemonReady(Socket* daemon_socket) override {
363 // Send the forward command to the daemon.
364 CHECK_EQ(static_cast<long>(command_pickle_.size()),
365 daemon_socket->WriteNumBytes(command_pickle_.data(),
366 command_pickle_.size()));
368 const int bytes_read = daemon_socket->Read(
369 buf, sizeof(buf) - 1 /* leave space for null terminator */);
370 CHECK_GT(bytes_read, 0);
371 DCHECK(static_cast<size_t>(bytes_read) < sizeof(buf));
373 base::StringPiece msg(buf, bytes_read);
374 if (msg.starts_with("ERROR")) {
383 const Pickle command_pickle_;
387 void ExitWithUsage() {
388 std::cerr << "Usage: host_forwarder [options]\n\n"
390 " --serial-id=[0-9A-Z]{16}]\n"
391 " --map DEVICE_PORT HOST_PORT\n"
392 " --unmap DEVICE_PORT\n"
397 int PortToInt(const std::string& s) {
399 // Note that 0 is a valid port (used for dynamic port allocation).
400 if (!base::StringToInt(s, &value) || value < 0 ||
401 value > std::numeric_limits<uint16>::max()) {
402 LOG(ERROR) << "Could not convert string " << s << " to port";
408 int RunHostForwarder(int argc, char** argv) {
409 CommandLine::Init(argc, argv);
410 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess();
411 bool kill_server = false;
415 cmd_line.HasSwitch("serial-id") ?
416 cmd_line.GetSwitchValueASCII("serial-id") : std::string());
418 const std::vector<std::string> args = cmd_line.GetArgs();
419 if (cmd_line.HasSwitch("kill-server")) {
421 } else if (cmd_line.HasSwitch("unmap")) {
422 if (args.size() != 1)
424 // Note the minus sign below.
425 pickle.WriteInt(-PortToInt(args[0]));
426 } else if (cmd_line.HasSwitch("map")) {
427 if (args.size() != 2)
429 pickle.WriteInt(PortToInt(args[0]));
430 pickle.WriteInt(PortToInt(args[1]));
435 if (kill_server && args.size() > 0)
438 ClientDelegate client_delegate(pickle);
439 ServerDelegate daemon_delegate;
441 kLogFilePath, kDaemonIdentifier, &client_delegate, &daemon_delegate,
445 return !daemon.Kill();
446 if (!daemon.SpawnIfNeeded())
449 return client_delegate.has_failed() || daemon_delegate.has_failed();
453 } // namespace forwarder2
455 int main(int argc, char** argv) {
456 return forwarder2::RunHostForwarder(argc, argv);