Merge "Add native vsock support to ADB."
This commit is contained in:
commit
d290bb7ed8
7 changed files with 208 additions and 25 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
49
adb/sysdeps/vm_sockets.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue