device_controller.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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. 4 5#include "tools/android/forwarder2/device_controller.h" 6 7#include <errno.h> 8#include <stdlib.h> 9 10#include "base/logging.h" 11#include "base/memory/scoped_ptr.h" 12#include "base/safe_strerror_posix.h" 13#include "tools/android/forwarder2/command.h" 14#include "tools/android/forwarder2/device_listener.h" 15#include "tools/android/forwarder2/socket.h" 16 17namespace forwarder2 { 18 19DeviceController::DeviceController(int exit_notifier_fd) 20 : exit_notifier_fd_(exit_notifier_fd) { 21 kickstart_adb_socket_.set_exit_notifier_fd(exit_notifier_fd); 22} 23 24DeviceController::~DeviceController() { 25 KillAllListeners(); 26 CleanUpDeadListeners(); 27 CHECK_EQ(0, listeners_.size()); 28} 29 30void DeviceController::CleanUpDeadListeners() { 31 // Clean up dead listeners. 32 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { 33 if (!it.GetCurrentValue()->is_alive()) 34 // Remove deletes the listener. 35 listeners_.Remove(it.GetCurrentKey()); 36 } 37} 38 39void DeviceController::KillAllListeners() { 40 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) 41 it.GetCurrentValue()->ForceExit(); 42 for (ListenersMap::iterator it(&listeners_); !it.IsAtEnd(); it.Advance()) { 43 it.GetCurrentValue()->Join(); 44 CHECK(!it.GetCurrentValue()->is_alive()); 45 } 46} 47 48bool DeviceController::Init(const std::string& adb_unix_socket) { 49 if (!kickstart_adb_socket_.BindUnix(adb_unix_socket, 50 true /* abstract */)) { 51 LOG(ERROR) << "Could not BindAndListen DeviceController socket on port " 52 << adb_unix_socket << ": " << safe_strerror(errno); 53 return false; 54 } 55 LOG(INFO) << "Listening on Unix Domain Socket " << adb_unix_socket; 56 return true; 57} 58 59void DeviceController::Start() { 60 while (true) { 61 CleanUpDeadListeners(); 62 scoped_ptr<Socket> socket(new Socket); 63 if (!kickstart_adb_socket_.Accept(socket.get())) { 64 if (!kickstart_adb_socket_.exited()) { 65 LOG(ERROR) << "Could not Accept DeviceController socket: " 66 << safe_strerror(errno); 67 } else { 68 LOG(INFO) << "Received exit notification"; 69 } 70 break; 71 } 72 // So that |socket| doesn't block on read if it has notifications. 73 socket->set_exit_notifier_fd(exit_notifier_fd_); 74 int port; 75 command::Type command; 76 if (!ReadCommand(socket.get(), &port, &command)) { 77 LOG(ERROR) << "Invalid command received."; 78 continue; 79 } 80 DeviceListener* listener = listeners_.Lookup(port); 81 switch (command) { 82 case command::LISTEN: { 83 if (listener != NULL) { 84 LOG(WARNING) << "Already forwarding port " << port 85 << ". Attempting to restart the listener.\n"; 86 listener->ForceExit(); 87 listener->Join(); 88 CHECK(!listener->is_alive()); 89 // Remove deletes the listener object. 90 listeners_.Remove(port); 91 } 92 scoped_ptr<DeviceListener> new_listener( 93 new DeviceListener(socket.Pass(), port)); 94 if (!new_listener->BindListenerSocket()) 95 continue; 96 new_listener->Start(); 97 // |port| can be zero, to allow dynamically allocated port, so instead, 98 // we call DeviceListener::listener_port() to retrieve the currently 99 // allocated port to this new listener, which has been set by the 100 // BindListenerSocket() method in case of success. 101 const int listener_port = new_listener->listener_port(); 102 // |new_listener| is now owned by listeners_ map. 103 listeners_.AddWithID(new_listener.release(), listener_port); 104 LOG(INFO) << "Forwarding device port " << listener_port << " to host."; 105 break; 106 } 107 case command::DATA_CONNECTION: 108 if (listener == NULL) { 109 LOG(ERROR) << "Data Connection command received, but " 110 << "listener has not been set up yet for port " << port; 111 // After this point it is assumed that, once we close our Adb Data 112 // socket, the Adb forwarder command will propagate the closing of 113 // sockets all the way to the host side. 114 continue; 115 } else if (!listener->SetAdbDataSocket(socket.Pass())) { 116 LOG(ERROR) << "Could not set Adb Data Socket for port: " << port; 117 // Same assumption as above, but in this case the socket is closed 118 // inside SetAdbDataSocket. 119 continue; 120 } 121 break; 122 default: 123 // TODO(felipeg): add a KillAllListeners command. 124 LOG(ERROR) << "Invalid command received. Port: " << port 125 << " Command: " << command; 126 } 127 } 128 KillAllListeners(); 129 CleanUpDeadListeners(); 130} 131 132} // namespace forwarder 133