Merge "Add native vsock support to ADB." am: d290bb7ed8 am: 8435ddc499

am: 00a8d2693f

Change-Id: I5fc12d468a710dcca271ba1f03b6a939675b1cb2
This commit is contained in:
Cody Schuffelen 2019-01-25 21:45:32 -08:00 committed by android-build-merger
commit 6dbf6a491c
7 changed files with 208 additions and 25 deletions

View file

@ -1134,7 +1134,9 @@ bool handle_host_request(const char* service, TransportType type, const char* se
std::string host;
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
std::string error;
if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
if (address.starts_with("vsock:")) {
serial = address;
} 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;

View file

@ -78,7 +78,7 @@ void qemu_socket_thread(int port) {
/* This could be an older version of the emulator, that doesn't
* implement adb QEMUD service. Fall back to the old TCP way. */
D("adb service is not available. Falling back to TCP socket.");
std::thread(server_socket_thread, port).detach();
std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
return;
}

View file

@ -46,6 +46,11 @@ using android::base::StringPrintf;
#define ADB_WINDOWS 0
#endif
#if ADB_LINUX
#include <sys/socket.h>
#include "sysdeps/vm_sockets.h"
#endif
// Not static because it is used in commandline.c.
int gListenAll = 0;
@ -174,6 +179,62 @@ bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std
return true;
}
return false;
} else if (address.starts_with("vsock:")) {
#if ADB_LINUX
std::string spec_str(address);
std::vector<std::string> fragments = android::base::Split(spec_str, ":");
unsigned int port_value = port ? *port : 0;
if (fragments.size() != 2 && fragments.size() != 3) {
*error = android::base::StringPrintf("expected vsock:cid or vsock:port:cid in '%s'",
spec_str.c_str());
errno = EINVAL;
return false;
}
unsigned int cid = 0;
if (!android::base::ParseUint(fragments[1], &cid)) {
*error = android::base::StringPrintf("could not parse vsock cid in '%s'",
spec_str.c_str());
errno = EINVAL;
return false;
}
if (fragments.size() == 3 && !android::base::ParseUint(fragments[2], &port_value)) {
*error = android::base::StringPrintf("could not parse vsock port in '%s'",
spec_str.c_str());
errno = EINVAL;
return false;
}
if (port_value == 0) {
*error = android::base::StringPrintf("vsock port was not provided.");
errno = EINVAL;
return false;
}
fd->reset(socket(AF_VSOCK, SOCK_STREAM, 0));
if (fd->get() == -1) {
*error = "could not open vsock socket";
return false;
}
sockaddr_vm addr{};
addr.svm_family = AF_VSOCK;
addr.svm_port = port_value;
addr.svm_cid = cid;
if (serial) {
*serial = android::base::StringPrintf("vsock:%u:%d", cid, port_value);
}
if (connect(fd->get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
int error_num = errno;
*error = android::base::StringPrintf("could not connect to vsock address '%s'",
spec_str.c_str());
errno = error_num;
return false;
}
if (port) {
*port = port_value;
}
return true;
#else // ADB_LINUX
*error = "vsock is only supported on linux";
return false;
#endif // ADB_LINUX
}
for (const auto& it : kLocalSocketTypes) {
@ -187,6 +248,9 @@ bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std
fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
SOCK_STREAM, error));
if (serial) {
*serial = address;
}
return true;
}
}
@ -196,7 +260,7 @@ bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std
return false;
}
int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) {
int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_port) {
if (spec.starts_with("tcp:")) {
std::string hostname;
int port;
@ -215,10 +279,59 @@ int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_
return -1;
}
if (result >= 0 && port == 0 && resolved_tcp_port) {
*resolved_tcp_port = adb_socket_get_local_port(result);
if (result >= 0 && resolved_port) {
*resolved_port = adb_socket_get_local_port(result);
}
return result;
} else if (spec.starts_with("vsock:")) {
#if ADB_LINUX
std::string spec_str(spec);
std::vector<std::string> fragments = android::base::Split(spec_str, ":");
if (fragments.size() != 2) {
*error = "given vsock server socket string was invalid";
return -1;
}
int port;
if (!android::base::ParseInt(fragments[1], &port)) {
*error = "could not parse vsock port";
errno = EINVAL;
return -1;
} else if (port < 0) {
*error = "vsock port was negative.";
errno = EINVAL;
return -1;
}
unique_fd serverfd(socket(AF_VSOCK, SOCK_STREAM, 0));
if (serverfd == -1) {
int error_num = errno;
*error = android::base::StringPrintf("could not create vsock server: '%s'",
strerror(error_num));
errno = error_num;
return -1;
}
sockaddr_vm addr{};
addr.svm_family = AF_VSOCK;
addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port;
addr.svm_cid = VMADDR_CID_ANY;
socklen_t addr_len = sizeof(addr);
if (bind(serverfd, reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
return -1;
}
if (listen(serverfd, 4)) {
return -1;
}
if (serverfd >= 0 && resolved_port) {
if (getsockname(serverfd, reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
*resolved_port = addr.svm_port;
} else {
return -1;
}
}
return serverfd.release();
#else // ADB_LINUX
*error = "vsock is only supported on linux";
return -1;
#endif // ADB_LINUX
}
for (const auto& it : kLocalSocketTypes) {

View file

@ -609,6 +609,14 @@ bool parse_host_service(std::string_view* out_serial, std::string_view* out_comm
return false;
}
}
if (command.starts_with("vsock:")) {
// vsock serials are vsock:cid:port, which have an extra colon compared to tcp.
size_t next_colon = command.find(':');
if (next_colon == std::string::npos) {
return false;
}
consume(next_colon + 1);
}
bool found_address = false;
if (command[0] == '[') {

49
adb/sysdeps/vm_sockets.h Normal file
View file

@ -0,0 +1,49 @@
#if __BIONIC__
#include <linux/vm_sockets.h>
#else
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
*** Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h
***
****************************************************************************
****************************************************************************/
#ifndef _UAPI_VM_SOCKETS_H
#define _UAPI_VM_SOCKETS_H
#include <linux/socket.h>
#define SO_VM_SOCKETS_BUFFER_SIZE 0
#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1
#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2
#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3
#define SO_VM_SOCKETS_TRUSTED 5
#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6
#define SO_VM_SOCKETS_NONBLOCK_TXRX 7
#define VMADDR_CID_ANY -1U
#define VMADDR_PORT_ANY -1U
#define VMADDR_CID_HYPERVISOR 0
#define VMADDR_CID_RESERVED 1
#define VMADDR_CID_HOST 2
#define VM_SOCKETS_INVALID_VERSION -1U
#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24)
#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16)
#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF))
struct sockaddr_vm {
__kernel_sa_family_t svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) -
sizeof(unsigned int) - sizeof(unsigned int)];
};
#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
#ifndef AF_VSOCK
#define AF_VSOCK 40
#endif
#endif
#endif

View file

@ -28,6 +28,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_set>
@ -400,7 +401,7 @@ void send_packet(apacket* p, atransport* t);
asocket* create_device_tracker(bool long_output);
#if !ADB_HOST
void server_socket_thread(int port);
void server_socket_thread(std::string_view spec);
#if defined(__ANDROID__)
void qemu_socket_thread(int port);

View file

@ -26,6 +26,7 @@
#include <sys/types.h>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
@ -74,14 +75,15 @@ std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
unique_fd fd;
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
std::string serial;
if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
std::string prefix_addr = address.starts_with("vsock:") ? address : "tcp:" + address;
if (socket_spec_connect(&fd, prefix_addr, &port, &serial, response)) {
close_on_exec(fd);
if (!set_tcp_keepalive(fd, 1)) {
D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
}
return std::make_tuple(std::move(fd), port, serial);
}
return std::make_tuple(unique_fd(), 0, "");
return std::make_tuple(unique_fd(), 0, serial);
}
void connect_device(const std::string& address, std::string* response) {
@ -95,6 +97,9 @@ void connect_device(const std::string& address, std::string* response) {
int port;
std::string serial;
std::tie(fd, port, serial) = tcp_connect(address, response);
if (fd.get() == -1) {
return;
}
auto reconnect = [address](atransport* t) {
std::string response;
unique_fd fd;
@ -231,16 +236,20 @@ static void client_socket_thread(int) {
#else // !ADB_HOST
void server_socket_thread(int port) {
void server_socket_thread(std::string_view spec) {
unique_fd serverfd;
adb_thread_setname("server socket");
D("transport: server_socket_thread() starting");
int port;
while (serverfd == -1) {
std::string spec = android::base::StringPrintf("tcp:%d", port);
std::string error;
serverfd.reset(socket_spec_listen(spec, &error));
if (serverfd < 0) {
errno = 0;
serverfd.reset(socket_spec_listen(spec, &error, &port));
if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
D("unrecoverable error: '%s'", error.c_str());
return;
} else if (serverfd < 0) {
D("server: cannot bind socket yet: %s", error.c_str());
std::this_thread::sleep_for(1s);
continue;
@ -249,7 +258,8 @@ void server_socket_thread(int port) {
}
while (true) {
D("server: trying to get new connection from %d", port);
std::string spec_str{spec};
D("server: trying to get new connection from %s", spec_str.c_str());
unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr));
if (fd >= 0) {
D("server: new connection on fd %d", fd.get());
@ -266,25 +276,25 @@ void server_socket_thread(int port) {
#endif
void local_init(int port) {
void (*func)(int);
const char* debug_name = "";
#if ADB_HOST
func = client_socket_thread;
debug_name = "client";
D("transport: local client init");
std::thread(client_socket_thread, port).detach();
#elif !defined(__ANDROID__)
// Host adbd.
func = server_socket_thread;
debug_name = "server";
D("transport: local server init");
std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
#else
D("transport: local server init");
// For the adbd daemon in the system image we need to distinguish
// between the device, and the emulator.
func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
debug_name = "server";
if (use_qemu_goldfish()) {
std::thread(qemu_socket_thread, port).detach();
} else {
std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
}
std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
#endif // !ADB_HOST
D("transport: local %s init", debug_name);
std::thread(func, port).detach();
}
#if ADB_HOST