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