device_controller.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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_.AddEventFd(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 LOG(ERROR) << "Could not BindAndListen DeviceController socket on port " 51 << adb_unix_socket << ": " << safe_strerror(errno); 52 return false; 53 } 54 LOG(INFO) << "Listening on Unix Domain Socket " << adb_unix_socket; 55 return true; 56} 57 58void DeviceController::Start() { 59 while (true) { 60 CleanUpDeadListeners(); 61 scoped_ptr<Socket> socket(new Socket); 62 if (!kickstart_adb_socket_.Accept(socket.get())) { 63 if (!kickstart_adb_socket_.DidReceiveEvent()) { 64 LOG(ERROR) << "Could not Accept DeviceController socket: " 65 << safe_strerror(errno); 66 } else { 67 LOG(INFO) << "Received exit notification"; 68 } 69 break; 70 } 71 // So that |socket| doesn't block on read if it has notifications. 72 socket->AddEventFd(exit_notifier_fd_); 73 int port; 74 command::Type command; 75 if (!ReadCommand(socket.get(), &port, &command)) { 76 LOG(ERROR) << "Invalid command received."; 77 continue; 78 } 79 DeviceListener* listener = listeners_.Lookup(port); 80 switch (command) { 81 case command::LISTEN: { 82 if (listener != NULL) { 83 LOG(WARNING) << "Already forwarding port " << port 84 << ". Attempting to restart the listener.\n"; 85 listener->ForceExit(); 86 listener->Join(); 87 CHECK(!listener->is_alive()); 88 // Remove deletes the listener object. 89 listeners_.Remove(port); 90 } 91 scoped_ptr<DeviceListener> new_listener( 92 new DeviceListener(socket.Pass(), port)); 93 if (!new_listener->BindListenerSocket()) 94 continue; 95 new_listener->Start(); 96 // |port| can be zero, to allow dynamically allocated port, so instead, 97 // we call DeviceListener::listener_port() to retrieve the currently 98 // allocated port to this new listener, which has been set by the 99 // BindListenerSocket() method in case of success. 100 const int listener_port = new_listener->listener_port(); 101 // |new_listener| is now owned by listeners_ map. 102 listeners_.AddWithID(new_listener.release(), listener_port); 103 LOG(INFO) << "Forwarding device port " << listener_port << " to host."; 104 break; 105 } 106 case command::DATA_CONNECTION: 107 if (listener == NULL) { 108 LOG(ERROR) << "Data Connection command received, but " 109 << "listener has not been set up yet for port " << port; 110 // After this point it is assumed that, once we close our Adb Data 111 // socket, the Adb forwarder command will propagate the closing of 112 // sockets all the way to the host side. 113 continue; 114 } else if (!listener->SetAdbDataSocket(socket.Pass())) { 115 LOG(ERROR) << "Could not set Adb Data Socket for port: " << port; 116 // Same assumption as above, but in this case the socket is closed 117 // inside SetAdbDataSocket. 118 continue; 119 } 120 break; 121 default: 122 // TODO(felipeg): add a KillAllListeners command. 123 LOG(ERROR) << "Invalid command received. Port: " << port 124 << " Command: " << command; 125 } 126 } 127 KillAllListeners(); 128 CleanUpDeadListeners(); 129} 130 131} // namespace forwarder 132