Merge "Enable "localfilesystem" UNIX domain socket for ADB."
This commit is contained in:
commit
90e9217aca
11 changed files with 206 additions and 67 deletions
|
@ -1167,7 +1167,7 @@ HostRequestResult handle_host_request(std::string_view service, TransportType ty
|
|||
std::string host;
|
||||
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
std::string error;
|
||||
if (address.starts_with("vsock:")) {
|
||||
if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
|
||||
serial = address;
|
||||
} else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
|
||||
SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
|
||||
|
|
|
@ -200,7 +200,7 @@ void put_apacket(apacket* p);
|
|||
#define ADB_SUBCLASS 0x42
|
||||
#define ADB_PROTOCOL 0x1
|
||||
|
||||
void local_init(int port);
|
||||
void local_init(const std::string& addr);
|
||||
bool local_connect(int port);
|
||||
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply
|
|||
}
|
||||
|
||||
if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) {
|
||||
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
|
||||
local_init(android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
|
||||
}
|
||||
|
||||
std::string error;
|
||||
|
|
|
@ -32,11 +32,13 @@
|
|||
#include <sys/prctl.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <libminijail.h>
|
||||
|
@ -51,6 +53,7 @@
|
|||
#include "adb_auth.h"
|
||||
#include "adb_listeners.h"
|
||||
#include "adb_utils.h"
|
||||
#include "socket_spec.h"
|
||||
#include "transport.h"
|
||||
|
||||
#include "mdns.h"
|
||||
|
@ -179,12 +182,26 @@ static void drop_privileges(int server_port) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static void setup_port(int port) {
|
||||
LOG(INFO) << "adbd listening on port " << port;
|
||||
local_init(port);
|
||||
static void setup_adb(const std::vector<std::string>& addrs) {
|
||||
#if defined(__ANDROID__)
|
||||
// Get the first valid port from addrs and setup mDNS.
|
||||
int port = -1;
|
||||
std::string error;
|
||||
for (const auto& addr : addrs) {
|
||||
port = get_host_socket_spec_port(addr, &error);
|
||||
if (port != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (port == -1) {
|
||||
port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
}
|
||||
setup_mdns(port);
|
||||
#endif
|
||||
for (const auto& addr : addrs) {
|
||||
LOG(INFO) << "adbd listening on " << addr;
|
||||
local_init(addr);
|
||||
}
|
||||
}
|
||||
|
||||
int adbd_main(int server_port) {
|
||||
|
@ -248,25 +265,38 @@ int adbd_main(int server_port) {
|
|||
// If one of these properties is set, also listen on that port.
|
||||
// If one of the properties isn't set and we couldn't listen on usb, listen
|
||||
// on the default port.
|
||||
std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
|
||||
if (prop_port.empty()) {
|
||||
prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
|
||||
}
|
||||
std::vector<std::string> addrs;
|
||||
std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", "");
|
||||
if (prop_addr.empty()) {
|
||||
std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
|
||||
if (prop_port.empty()) {
|
||||
prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
|
||||
}
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
if (prop_port.empty() && getenv("ADBD_PORT")) {
|
||||
prop_port = getenv("ADBD_PORT");
|
||||
}
|
||||
if (prop_port.empty() && getenv("ADBD_PORT")) {
|
||||
prop_port = getenv("ADBD_PORT");
|
||||
}
|
||||
#endif
|
||||
|
||||
int port;
|
||||
if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
|
||||
D("using port=%d", port);
|
||||
// Listen on TCP port specified by service.adb.tcp.port property.
|
||||
setup_port(port);
|
||||
} else if (!is_usb) {
|
||||
// Listen on default port.
|
||||
setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
|
||||
int port;
|
||||
if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
|
||||
D("using tcp port=%d", port);
|
||||
// Listen on TCP and VSOCK port specified by service.adb.tcp.port property.
|
||||
addrs.push_back(android::base::StringPrintf("tcp:%d", port));
|
||||
addrs.push_back(android::base::StringPrintf("vsock:%d", port));
|
||||
setup_adb(addrs);
|
||||
} else if (!is_usb) {
|
||||
// Listen on default port.
|
||||
addrs.push_back(
|
||||
android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
|
||||
addrs.push_back(
|
||||
android::base::StringPrintf("vsock:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
|
||||
setup_adb(addrs);
|
||||
}
|
||||
} else {
|
||||
addrs = android::base::Split(prop_addr, ",");
|
||||
setup_adb(addrs);
|
||||
}
|
||||
|
||||
D("adbd_main(): pre init_jdwp()");
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <qemu_pipe.h>
|
||||
|
||||
#define TRACE_TAG TRANSPORT
|
||||
#include "socket_spec.h"
|
||||
#include "sysdeps.h"
|
||||
#include "transport.h"
|
||||
|
||||
|
@ -55,7 +56,7 @@
|
|||
* the transport registration is completed. That's why we need to send the
|
||||
* 'start' request after the transport is registered.
|
||||
*/
|
||||
void qemu_socket_thread(int port) {
|
||||
void qemu_socket_thread(std::string_view addr) {
|
||||
/* 'accept' request to the adb QEMUD service. */
|
||||
static const char _accept_req[] = "accept";
|
||||
/* 'start' request to the adb QEMUD service. */
|
||||
|
@ -69,6 +70,12 @@ void qemu_socket_thread(int port) {
|
|||
adb_thread_setname("qemu socket");
|
||||
D("transport: qemu_socket_thread() starting");
|
||||
|
||||
std::string error;
|
||||
int port = get_host_socket_spec_port(addr, &error);
|
||||
if (port == -1) {
|
||||
port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
}
|
||||
|
||||
/* adb QEMUD service connection request. */
|
||||
snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
|
||||
|
||||
|
@ -78,7 +85,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, tcp_listen_inaddr_any, port).detach();
|
||||
std::thread(server_socket_thread, adb_listen, addr).detach();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -122,6 +122,41 @@ bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* po
|
|||
return true;
|
||||
}
|
||||
|
||||
int get_host_socket_spec_port(std::string_view spec, std::string* error) {
|
||||
int port;
|
||||
if (spec.starts_with("tcp:")) {
|
||||
if (!parse_tcp_socket_spec(spec, nullptr, &port, nullptr, error)) {
|
||||
return -1;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
if (!android::base::ParseInt(fragments[1], &port)) {
|
||||
*error = "could not parse vsock port";
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (port < 0) {
|
||||
*error = "vsock port was negative.";
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#else // ADB_LINUX
|
||||
*error = "vsock is only supported on linux";
|
||||
return -1;
|
||||
#endif // ADB_LINUX
|
||||
} else {
|
||||
*error = "given socket spec string was invalid";
|
||||
return -1;
|
||||
}
|
||||
return port;
|
||||
}
|
||||
|
||||
static bool tcp_host_is_local(std::string_view hostname) {
|
||||
// FIXME
|
||||
return hostname.empty() || hostname == "localhost";
|
||||
|
@ -254,6 +289,14 @@ 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 (fd->get() < 0) {
|
||||
*error =
|
||||
android::base::StringPrintf("could not connect to %s address '%s'",
|
||||
it.first.c_str(), std::string(address).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (serial) {
|
||||
*serial = address;
|
||||
}
|
||||
|
@ -275,7 +318,11 @@ int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_
|
|||
}
|
||||
|
||||
int result;
|
||||
#if ADB_HOST
|
||||
if (hostname.empty() && gListenAll) {
|
||||
#else
|
||||
if (hostname.empty()) {
|
||||
#endif
|
||||
result = network_inaddr_any_server(port, SOCK_STREAM, error);
|
||||
} else if (tcp_host_is_local(hostname)) {
|
||||
result = network_loopback_server(port, SOCK_STREAM, error, true);
|
||||
|
|
|
@ -31,3 +31,5 @@ int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_
|
|||
|
||||
bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port,
|
||||
std::string* serial, std::string* error);
|
||||
|
||||
int get_host_socket_spec_port(std::string_view spec, std::string* error);
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(socket_spec, parse_tcp_socket_spec_just_port) {
|
||||
|
@ -88,3 +92,63 @@ TEST(socket_spec, parse_tcp_socket_spec_ipv6_bad_ports) {
|
|||
EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error));
|
||||
EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error));
|
||||
}
|
||||
|
||||
TEST(socket_spec, get_host_socket_spec_port) {
|
||||
std::string error;
|
||||
EXPECT_EQ(5555, get_host_socket_spec_port("tcp:5555", &error));
|
||||
EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost:5555", &error));
|
||||
EXPECT_EQ(5555, get_host_socket_spec_port("tcp:[::1]:5555", &error));
|
||||
EXPECT_EQ(5555, get_host_socket_spec_port("vsock:5555", &error));
|
||||
}
|
||||
|
||||
TEST(socket_spec, get_host_socket_spec_port_no_port) {
|
||||
std::string error;
|
||||
EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("vsock:localhost", &error));
|
||||
}
|
||||
|
||||
TEST(socket_spec, get_host_socket_spec_port_bad_ports) {
|
||||
std::string error;
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("tcp:65536", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("tcp:-5", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("vsock:-5", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("vsock:5:5555", &error));
|
||||
}
|
||||
|
||||
TEST(socket_spec, get_host_socket_spec_port_bad_string) {
|
||||
std::string error;
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("tcpz:5555", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("vsockz:5555", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("abcd:5555", &error));
|
||||
EXPECT_EQ(-1, get_host_socket_spec_port("abcd", &error));
|
||||
}
|
||||
|
||||
TEST(socket_spec, socket_spec_listen_connect_tcp) {
|
||||
std::string error, serial;
|
||||
int port;
|
||||
unique_fd server_fd, client_fd;
|
||||
EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
|
||||
server_fd.reset(socket_spec_listen("tcp:7777", &error, &port));
|
||||
EXPECT_NE(server_fd.get(), -1);
|
||||
EXPECT_TRUE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
|
||||
EXPECT_NE(client_fd.get(), -1);
|
||||
}
|
||||
|
||||
TEST(socket_spec, socket_spec_listen_connect_localfilesystem) {
|
||||
std::string error, serial;
|
||||
int port;
|
||||
unique_fd server_fd, client_fd;
|
||||
TemporaryDir sock_dir;
|
||||
|
||||
// Only run this test if the created directory is writable.
|
||||
int result = access(sock_dir.path, W_OK);
|
||||
if (result == 0) {
|
||||
std::string sock_addr =
|
||||
android::base::StringPrintf("localfilesystem:%s/af_unix_socket", sock_dir.path);
|
||||
EXPECT_FALSE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
|
||||
server_fd.reset(socket_spec_listen(sock_addr, &error, &port));
|
||||
EXPECT_NE(server_fd.get(), -1);
|
||||
EXPECT_TRUE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
|
||||
EXPECT_NE(client_fd.get(), -1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -625,7 +625,8 @@ bool parse_host_service(std::string_view* out_serial, std::string_view* out_comm
|
|||
return true;
|
||||
};
|
||||
|
||||
static constexpr std::string_view prefixes[] = {"usb:", "product:", "model:", "device:"};
|
||||
static constexpr std::string_view prefixes[] = {
|
||||
"usb:", "product:", "model:", "device:", "localfilesystem:"};
|
||||
for (std::string_view prefix : prefixes) {
|
||||
if (command.starts_with(prefix)) {
|
||||
consume(prefix.size());
|
||||
|
|
|
@ -424,11 +424,12 @@ void send_packet(apacket* p, atransport* t);
|
|||
asocket* create_device_tracker(bool long_output);
|
||||
|
||||
#if !ADB_HOST
|
||||
unique_fd tcp_listen_inaddr_any(int port, std::string* error);
|
||||
void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_func, int port);
|
||||
unique_fd adb_listen(std::string_view addr, std::string* error);
|
||||
void server_socket_thread(std::function<unique_fd(std::string_view, std::string*)> listen_func,
|
||||
std::string_view addr);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
void qemu_socket_thread(int port);
|
||||
void qemu_socket_thread(std::string_view addr);
|
||||
bool use_qemu_goldfish();
|
||||
#endif
|
||||
|
||||
|
|
|
@ -85,22 +85,6 @@ bool local_connect(int port) {
|
|||
return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
|
||||
}
|
||||
|
||||
std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
|
||||
std::string* response) {
|
||||
unique_fd fd;
|
||||
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
|
||||
std::string serial;
|
||||
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, serial);
|
||||
}
|
||||
|
||||
void connect_device(const std::string& address, std::string* response) {
|
||||
if (address.empty()) {
|
||||
*response = "empty address";
|
||||
|
@ -110,17 +94,25 @@ void connect_device(const std::string& address, std::string* response) {
|
|||
D("connection requested to '%s'", address.c_str());
|
||||
unique_fd fd;
|
||||
int port;
|
||||
std::string serial;
|
||||
std::tie(fd, port, serial) = tcp_connect(address, response);
|
||||
std::string serial, prefix_addr;
|
||||
|
||||
// If address does not match any socket type, it should default to TCP.
|
||||
if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
|
||||
prefix_addr = address;
|
||||
} else {
|
||||
prefix_addr = "tcp:" + address;
|
||||
}
|
||||
|
||||
socket_spec_connect(&fd, prefix_addr, &port, &serial, response);
|
||||
if (fd.get() == -1) {
|
||||
return;
|
||||
}
|
||||
auto reconnect = [address](atransport* t) {
|
||||
auto reconnect = [prefix_addr](atransport* t) {
|
||||
std::string response;
|
||||
unique_fd fd;
|
||||
int port;
|
||||
std::string serial;
|
||||
std::tie(fd, port, serial) = tcp_connect(address, &response);
|
||||
socket_spec_connect(&fd, prefix_addr, &port, &serial, &response);
|
||||
if (fd == -1) {
|
||||
D("reconnect failed: %s", response.c_str());
|
||||
return ReconnectResult::Retry;
|
||||
|
@ -203,7 +195,7 @@ static std::vector<RetryPort>& retry_ports = *new std::vector<RetryPort>;
|
|||
std::mutex &retry_ports_lock = *new std::mutex;
|
||||
std::condition_variable &retry_ports_cond = *new std::condition_variable;
|
||||
|
||||
static void client_socket_thread(int) {
|
||||
static void client_socket_thread(std::string_view) {
|
||||
adb_thread_setname("client_socket_thread");
|
||||
D("transport: client_socket_thread() starting");
|
||||
PollAllLocalPortsForEmulator();
|
||||
|
@ -248,7 +240,8 @@ static void client_socket_thread(int) {
|
|||
|
||||
#else // !ADB_HOST
|
||||
|
||||
void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_func, int port) {
|
||||
void server_socket_thread(std::function<unique_fd(std::string_view, std::string*)> listen_func,
|
||||
std::string_view addr) {
|
||||
adb_thread_setname("server socket");
|
||||
|
||||
unique_fd serverfd;
|
||||
|
@ -256,7 +249,7 @@ void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_fun
|
|||
|
||||
while (serverfd == -1) {
|
||||
errno = 0;
|
||||
serverfd = listen_func(port, &error);
|
||||
serverfd = listen_func(addr, &error);
|
||||
if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
|
||||
D("unrecoverable error: '%s'", error.c_str());
|
||||
return;
|
||||
|
@ -276,7 +269,9 @@ void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_fun
|
|||
close_on_exec(fd.get());
|
||||
disable_tcp_nagle(fd.get());
|
||||
std::string serial = android::base::StringPrintf("host-%d", fd.get());
|
||||
register_socket_transport(std::move(fd), std::move(serial), port, 1,
|
||||
// We don't care about port value in "register_socket_transport" as it is used
|
||||
// only from ADB_HOST. "server_socket_thread" is never called from ADB_HOST.
|
||||
register_socket_transport(std::move(fd), std::move(serial), 0, 1,
|
||||
[](atransport*) { return ReconnectResult::Abort; });
|
||||
}
|
||||
}
|
||||
|
@ -285,38 +280,30 @@ void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_fun
|
|||
|
||||
#endif
|
||||
|
||||
unique_fd tcp_listen_inaddr_any(int port, std::string* error) {
|
||||
return unique_fd{network_inaddr_any_server(port, SOCK_STREAM, error)};
|
||||
}
|
||||
|
||||
#if !ADB_HOST
|
||||
static unique_fd vsock_listen(int port, std::string* error) {
|
||||
return unique_fd{
|
||||
socket_spec_listen(android::base::StringPrintf("vsock:%d", port), error, nullptr)
|
||||
};
|
||||
unique_fd adb_listen(std::string_view addr, std::string* error) {
|
||||
return unique_fd{socket_spec_listen(addr, error, nullptr)};
|
||||
}
|
||||
#endif
|
||||
|
||||
void local_init(int port) {
|
||||
void local_init(const std::string& addr) {
|
||||
#if ADB_HOST
|
||||
D("transport: local client init");
|
||||
std::thread(client_socket_thread, port).detach();
|
||||
std::thread(client_socket_thread, addr).detach();
|
||||
adb_local_transport_max_port_env_override();
|
||||
#elif !defined(__ANDROID__)
|
||||
// Host adbd.
|
||||
D("transport: local server init");
|
||||
std::thread(server_socket_thread, tcp_listen_inaddr_any, port).detach();
|
||||
std::thread(server_socket_thread, vsock_listen, port).detach();
|
||||
std::thread(server_socket_thread, adb_listen, addr).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.
|
||||
if (use_qemu_goldfish()) {
|
||||
std::thread(qemu_socket_thread, port).detach();
|
||||
if (addr.starts_with("tcp:") && use_qemu_goldfish()) {
|
||||
std::thread(qemu_socket_thread, addr).detach();
|
||||
} else {
|
||||
std::thread(server_socket_thread, tcp_listen_inaddr_any, port).detach();
|
||||
std::thread(server_socket_thread, adb_listen, addr).detach();
|
||||
}
|
||||
std::thread(server_socket_thread, vsock_listen, port).detach();
|
||||
#endif // !ADB_HOST
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue