adb: tell the client what transport it received.

Prerequisite for making `adb root` wait for the device that it told to
restart to disappear: the client needs to know which transport to wait
on.

Bug: http://b/124244488
Test: manual
Change-Id: I474559838ad7c0e961e9d2a98c902bca3b60d6c8
This commit is contained in:
Josh Gao 2019-02-20 20:37:26 -08:00
parent 2df76b7ee7
commit 79797ecbb1
5 changed files with 142 additions and 78 deletions

View file

@ -1018,8 +1018,9 @@ static int SendOkay(int fd, const std::string& s) {
return 0;
}
bool handle_host_request(std::string_view service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd, asocket* s) {
HostRequestResult handle_host_request(std::string_view service, TransportType type,
const char* serial, TransportId transport_id, int reply_fd,
asocket* s) {
if (service == "kill") {
fprintf(stderr, "adb server killed by remote request\n");
fflush(stdout);
@ -1032,29 +1033,49 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
exit(0);
}
// "transport:" is used for switching transport with a specified serial number
// "transport-usb:" is used for switching transport to the only USB transport
// "transport-local:" is used for switching transport to the only local transport
// "transport-any:" is used for switching transport to the only transport
if (service.starts_with("transport")) {
LOG(DEBUG) << "handle_host_request(" << service << ")";
// Transport selection:
if (service.starts_with("transport") || service.starts_with("tport:")) {
TransportType type = kTransportAny;
std::string serial_storage;
bool legacy = true;
if (ConsumePrefix(&service, "transport-id:")) {
if (!ParseUint(&transport_id, service)) {
SendFail(reply_fd, "invalid transport id");
return true;
// New transport selection protocol:
// This is essentially identical to the previous version, except it returns the selected
// transport id to the caller as well.
if (ConsumePrefix(&service, "tport:")) {
legacy = false;
if (ConsumePrefix(&service, "serial:")) {
serial_storage = service;
serial = serial_storage.c_str();
} else if (service == "usb") {
type = kTransportUsb;
} else if (service == "local") {
type = kTransportLocal;
} else if (service == "any") {
type = kTransportAny;
}
// Selection by id is unimplemented, since you obviously already know the transport id
// you're connecting to.
} else {
if (ConsumePrefix(&service, "transport-id:")) {
if (!ParseUint(&transport_id, service)) {
SendFail(reply_fd, "invalid transport id");
return HostRequestResult::Handled;
}
} else if (service == "transport-usb") {
type = kTransportUsb;
} else if (service == "transport-local") {
type = kTransportLocal;
} else if (service == "transport-any") {
type = kTransportAny;
} else if (ConsumePrefix(&service, "transport:")) {
serial_storage = service;
serial = serial_storage.c_str();
}
} else if (service == "transport-usb") {
type = kTransportUsb;
} else if (service == "transport-local") {
type = kTransportLocal;
} else if (service == "transport-any") {
type = kTransportAny;
} else if (ConsumePrefix(&service, "transport:")) {
serial_storage = service;
serial = serial_storage.c_str();
}
std::string error;
@ -1063,11 +1084,15 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
s->transport = t;
SendOkay(reply_fd);
// We succesfully handled the device selection, but there's another request coming.
return false;
if (!legacy) {
// Nothing we can do if this fails.
WriteFdExactly(reply_fd, &t->id, sizeof(t->id));
}
return HostRequestResult::SwitchedTransport;
} else {
SendFail(reply_fd, error);
return true;
return HostRequestResult::Handled;
}
}
@ -1078,7 +1103,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
std::string device_list = list_transports(long_listing);
D("Sending device list...");
SendOkay(reply_fd, device_list);
return true;
return HostRequestResult::Handled;
}
if (service == "reconnect-offline") {
@ -1094,7 +1119,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
response.resize(response.size() - 1);
}
SendOkay(reply_fd, response);
return true;
return HostRequestResult::Handled;
}
if (service == "features") {
@ -1105,7 +1130,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
} else {
SendFail(reply_fd, error);
}
return true;
return HostRequestResult::Handled;
}
if (service == "host-features") {
@ -1116,7 +1141,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
}
features.insert(kFeaturePushSync);
SendOkay(reply_fd, FeatureSetToString(features));
return true;
return HostRequestResult::Handled;
}
// remove TCP transport
@ -1125,7 +1150,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
if (address.empty()) {
kick_all_tcp_devices();
SendOkay(reply_fd, "disconnected everything");
return true;
return HostRequestResult::Handled;
}
std::string serial;
@ -1137,22 +1162,22 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
} else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
address.c_str(), error.c_str()));
return true;
return HostRequestResult::Handled;
}
atransport* t = find_transport(serial.c_str());
if (t == nullptr) {
SendFail(reply_fd, android::base::StringPrintf("no such device '%s'", serial.c_str()));
return true;
return HostRequestResult::Handled;
}
kick_transport(t);
SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
return true;
return HostRequestResult::Handled;
}
// Returns our value for ADB_SERVER_VERSION.
if (service == "version") {
SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
return true;
return HostRequestResult::Handled;
}
// These always report "unknown" rather than the actual error, for scripts.
@ -1164,7 +1189,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
} else {
SendFail(reply_fd, error);
}
return true;
return HostRequestResult::Handled;
}
if (service == "get-devpath") {
std::string error;
@ -1174,7 +1199,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
} else {
SendFail(reply_fd, error);
}
return true;
return HostRequestResult::Handled;
}
if (service == "get-state") {
std::string error;
@ -1184,7 +1209,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
} else {
SendFail(reply_fd, error);
}
return true;
return HostRequestResult::Handled;
}
// Indicates a new emulator instance has started.
@ -1197,7 +1222,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
}
/* we don't even need to send a reply */
return true;
return HostRequestResult::Handled;
}
if (service == "reconnect") {
@ -1209,7 +1234,7 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
"reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n";
}
SendOkay(reply_fd, response);
return true;
return HostRequestResult::Handled;
}
// TODO: Switch handle_forward_request to string_view.
@ -1220,10 +1245,10 @@ bool handle_host_request(std::string_view service, TransportType type, const cha
return acquire_one_transport(type, serial, transport_id, nullptr, error);
},
reply_fd)) {
return true;
return HostRequestResult::Handled;
}
return false;
return HostRequestResult::Unhandled;
}
static auto& init_mutex = *new std::mutex();

View file

@ -219,8 +219,15 @@ extern const char* adb_device_banner;
#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
#endif
bool handle_host_request(std::string_view service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd, asocket* s);
enum class HostRequestResult {
Handled,
SwitchedTransport,
Unhandled,
};
HostRequestResult handle_host_request(std::string_view service, TransportType type,
const char* serial, TransportId transport_id, int reply_fd,
asocket* s);
void handle_online(atransport* t);
void handle_offline(atransport* t);

View file

@ -70,46 +70,60 @@ void adb_set_socket_spec(const char* socket_spec) {
__adb_server_socket_spec = socket_spec;
}
static int switch_socket_transport(int fd, std::string* error) {
static std::optional<TransportId> switch_socket_transport(int fd, std::string* error) {
TransportId result;
bool read_transport = true;
std::string service;
if (__adb_transport_id) {
read_transport = false;
service += "host:transport-id:";
service += std::to_string(__adb_transport_id);
result = __adb_transport_id;
} else if (__adb_serial) {
service += "host:transport:";
service += "host:tport:serial:";
service += __adb_serial;
} else {
const char* transport_type = "???";
switch (__adb_transport) {
case kTransportUsb:
transport_type = "transport-usb";
break;
transport_type = "usb";
break;
case kTransportLocal:
transport_type = "transport-local";
break;
transport_type = "local";
break;
case kTransportAny:
transport_type = "transport-any";
break;
transport_type = "any";
break;
case kTransportHost:
// no switch necessary
return 0;
}
service += "host:";
service += "host:tport:";
service += transport_type;
}
if (!SendProtocolString(fd, service)) {
*error = perror_str("write failure during connection");
return -1;
return std::nullopt;
}
D("Switch transport in progress");
LOG(DEBUG) << "Switch transport in progress: " << service;
if (!adb_status(fd, error)) {
D("Switch transport failed: %s", error->c_str());
return -1;
return std::nullopt;
}
if (read_transport) {
if (!ReadFdExactly(fd, &result, sizeof(result))) {
*error = "failed to read transport id from server";
return std::nullopt;
}
}
D("Switch transport success");
return 0;
return result;
}
bool adb_status(int fd, std::string* error) {
@ -133,11 +147,10 @@ bool adb_status(int fd, std::string* error) {
return false;
}
static int _adb_connect(const std::string& service, std::string* error) {
D("_adb_connect: %s", service.c_str());
static int _adb_connect(std::string_view service, TransportId* transport, std::string* error) {
LOG(DEBUG) << "_adb_connect: " << service;
if (service.empty() || service.size() > MAX_PAYLOAD) {
*error = android::base::StringPrintf("bad service name length (%zd)",
service.size());
*error = android::base::StringPrintf("bad service name length (%zd)", service.size());
return -1;
}
@ -149,8 +162,15 @@ static int _adb_connect(const std::string& service, std::string* error) {
return -2;
}
if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd.get(), error)) {
return -1;
if (!service.starts_with("host")) {
std::optional<TransportId> transport_result = switch_socket_transport(fd.get(), error);
if (!transport_result) {
return -1;
}
if (transport) {
*transport = *transport_result;
}
}
if (!SendProtocolString(fd.get(), service)) {
@ -190,11 +210,15 @@ bool adb_kill_server() {
return true;
}
int adb_connect(const std::string& service, std::string* error) {
// first query the adb server's version
unique_fd fd(_adb_connect("host:version", error));
int adb_connect(std::string_view service, std::string* error) {
return adb_connect(nullptr, service, error);
}
D("adb_connect: service %s", service.c_str());
int adb_connect(TransportId* transport, std::string_view service, std::string* error) {
// first query the adb server's version
unique_fd fd(_adb_connect("host:version", nullptr, error));
LOG(DEBUG) << "adb_connect: service: " << service;
if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
fprintf(stderr, "* cannot start server on remote host\n");
// error is the original network connection error
@ -216,7 +240,7 @@ int adb_connect(const std::string& service, std::string* error) {
// Fall through to _adb_connect.
} else {
// If a server is already running, check its version matches.
int version = ADB_SERVER_VERSION - 1;
int version = 0;
// If we have a file descriptor, then parse version result.
if (fd >= 0) {
@ -254,7 +278,7 @@ int adb_connect(const std::string& service, std::string* error) {
return 0;
}
fd.reset(_adb_connect(service, error));
fd.reset(_adb_connect(service, transport, error));
if (fd == -1) {
D("_adb_connect error: %s", error->c_str());
} else if(fd == -2) {
@ -265,7 +289,6 @@ int adb_connect(const std::string& service, std::string* error) {
return fd.release();
}
bool adb_command(const std::string& service) {
std::string error;
unique_fd fd(adb_connect(service, &error));

View file

@ -24,7 +24,10 @@
// Connect to adb, connect to the named service, and return a valid fd for
// interacting with that service upon success or a negative number on failure.
int adb_connect(const std::string& service, std::string* _Nonnull error);
int adb_connect(std::string_view service, std::string* _Nonnull error);
// Same as above, except returning the TransportId for the service that we've connected to.
int adb_connect(TransportId* _Nullable id, std::string_view service, std::string* _Nonnull error);
// Kill the currently running adb server, if it exists.
bool adb_kill_server();

View file

@ -792,16 +792,22 @@ static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
// Some requests are handled immediately -- in that case the handle_host_request() routine
// has sent the OKAY or FAIL message and all we have to do is clean up.
if (handle_host_request(service, type,
serial.empty() ? nullptr : std::string(serial).c_str(),
transport_id, s->peer->fd, s)) {
LOG(VERBOSE) << "SS(" << s->id << "): handled host service '" << service << "'";
goto fail;
}
if (service.starts_with("transport")) {
D("SS(%d): okay transport", s->id);
s->smart_socket_data.clear();
return 0;
auto host_request_result = handle_host_request(
service, type, serial.empty() ? nullptr : std::string(serial).c_str(), transport_id,
s->peer->fd, s);
switch (host_request_result) {
case HostRequestResult::Handled:
LOG(VERBOSE) << "SS(" << s->id << "): handled host service '" << service << "'";
goto fail;
case HostRequestResult::SwitchedTransport:
D("SS(%d): okay transport", s->id);
s->smart_socket_data.clear();
return 0;
case HostRequestResult::Unhandled:
break;
}
/* try to find a local service with this name.