diff --git a/adb/adb.cpp b/adb/adb.cpp index 9b663be91..460ddde55 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -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", diff --git a/adb/adb.h b/adb/adb.h index c6cb06aff..e7fcc9125 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -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); diff --git a/adb/client/main.cpp b/adb/client/main.cpp index 0c5c28f1b..e5ffe4c09 100644 --- a/adb/client/main.cpp +++ b/adb/client/main.cpp @@ -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; diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp index 7277cc829..3322574ce 100644 --- a/adb/daemon/main.cpp +++ b/adb/daemon/main.cpp @@ -32,11 +32,13 @@ #include #include +#include #include #include #include #include +#include #if defined(__ANDROID__) #include @@ -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& 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 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()"); diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp index aa760bcb3..901efeea2 100644 --- a/adb/daemon/transport_qemu.cpp +++ b/adb/daemon/transport_qemu.cpp @@ -18,6 +18,7 @@ #include #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; } diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp index 27e8c4605..2d1ea56fa 100644 --- a/adb/socket_spec.cpp +++ b/adb/socket_spec.cpp @@ -119,6 +119,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 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"; @@ -248,6 +283,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; } @@ -269,7 +312,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); diff --git a/adb/socket_spec.h b/adb/socket_spec.h index 7cc2fac57..94719c811 100644 --- a/adb/socket_spec.h +++ b/adb/socket_spec.h @@ -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); diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp index 3a2f60c3b..e9d5270ca 100644 --- a/adb/socket_spec_test.cpp +++ b/adb/socket_spec_test.cpp @@ -18,6 +18,10 @@ #include +#include + +#include +#include #include 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); + } +} diff --git a/adb/sockets.cpp b/adb/sockets.cpp index 7d5bf17c7..423af67f1 100644 --- a/adb/sockets.cpp +++ b/adb/sockets.cpp @@ -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()); diff --git a/adb/transport.h b/adb/transport.h index 89d76b8c9..dae438ce5 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -423,11 +423,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 listen_func, int port); +unique_fd adb_listen(std::string_view addr, std::string* error); +void server_socket_thread(std::function 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 diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp index b9f738dfc..c72618603 100644 --- a/adb/transport_local.cpp +++ b/adb/transport_local.cpp @@ -85,22 +85,6 @@ bool local_connect(int port) { return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0; } -std::tuple 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& retry_ports = *new std::vector; 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 listen_func, int port) { +void server_socket_thread(std::function listen_func, + std::string_view addr) { adb_thread_setname("server socket"); unique_fd serverfd; @@ -256,7 +249,7 @@ void server_socket_thread(std::function 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 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 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 }