Enable "localfilesystem" UNIX domain socket for ADB.

This patch introduce "service.adb.listen_addrs", a new
string type property, while keeping the old properties.
The new property added in this patch is used to listen
on UNIX domain socket "localfilesystem".

"service.adb.listen_addrs" can be used to listen on
multiple addresses, such as tcp:5555 and tcp:5556.
It is separated by ',' (comma) character.

In the process of introducing the new socket type, the
method tcp_connect is removed and combined into
socket_spec_connect.

Without specifying using the new property, adb will
try to listen on both tcp and vsock (following the
previous implementation).

Some examples of the new property value are:
  - "tcp:5555"
  - "vsock:5555"
  - "localfilesystem:/tmp/test"
  - "tcp:5555,vsock:5555"

Bug: 133378083
Test: On master-arc-dev:
        adb root;
        setprop service.adb.listen_addrs localfilesystem:
	    <path_to_socket>;
        adb connect localfilesystem:<path_to_socket>;
        adb -s localfilesystem:<path_to_socket> shell;
	    inside Chrome OS.
Test: On aosp_bluefin:
        setprop service.adb.listen_addr tcp:5555;
        adb connect <IP>:5555; adb shell;
Test: On aosp_bluefin:
        setprop service.adb.tcp.port 5555;
        adb connect <IP>:5555; adb shell;
Test: On aosp_bluefin:
        setprop service.adb.listen_addrs tcp:5555,tcp:6666;
        adb connect <IP>:5555; adb shell;
        adb connect <IP>:6666; adb shell;
Test: On aosp_bluefin:
        ./adb_test;
Test: On cuttlefish:
        launch_cvd;
        adb -s 127.0.0.1:6520 shell;
Test: Ran host tests:
        ./adb_test;
        ./adb_integration_test_adb;
        ./adb_integration_test_device;

Change-Id: I8289bf0ab3305cf23ce5695ffba46845d58ef6bb
diff --git a/adb.cpp b/adb.cpp
index 9b663be..460ddde 100644
--- a/adb.cpp
+++ b/adb.cpp
@@ -1167,7 +1167,7 @@
         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.h b/adb.h
index c6cb06a..e7fcc91 100644
--- a/adb.h
+++ b/adb.h
@@ -200,7 +200,7 @@
 #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/client/main.cpp b/client/main.cpp
index 0c5c28f..e5ffe4c 100644
--- a/client/main.cpp
+++ b/client/main.cpp
@@ -129,7 +129,7 @@
     }
 
     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/daemon/main.cpp b/daemon/main.cpp
index 7277cc8..3322574 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -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 @@
 }
 #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 @@
     // 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()");
diff --git a/daemon/transport_qemu.cpp b/daemon/transport_qemu.cpp
index aa760bc..901efee 100644
--- a/daemon/transport_qemu.cpp
+++ b/daemon/transport_qemu.cpp
@@ -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 @@
     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 @@
         /* 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/socket_spec.cpp b/socket_spec.cpp
index 27e8c46..2d1ea56 100644
--- a/socket_spec.cpp
+++ b/socket_spec.cpp
@@ -119,6 +119,41 @@
     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";
@@ -248,6 +283,14 @@
 
             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 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/socket_spec.h b/socket_spec.h
index 7cc2fac..94719c8 100644
--- a/socket_spec.h
+++ b/socket_spec.h
@@ -31,3 +31,5 @@
 
 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/socket_spec_test.cpp b/socket_spec_test.cpp
index 3a2f60c..e9d5270 100644
--- a/socket_spec_test.cpp
+++ b/socket_spec_test.cpp
@@ -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 @@
     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/sockets.cpp b/sockets.cpp
index 7d5bf17..423af67 100644
--- a/sockets.cpp
+++ b/sockets.cpp
@@ -625,7 +625,8 @@
         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/transport.h b/transport.h
index 89d76b8..dae438c 100644
--- a/transport.h
+++ b/transport.h
@@ -423,11 +423,12 @@
 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
 
diff --git a/transport_local.cpp b/transport_local.cpp
index b9f738d..c726186 100644
--- a/transport_local.cpp
+++ b/transport_local.cpp
@@ -85,22 +85,6 @@
     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 @@
     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 @@
 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 @@
 
 #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 @@
 
     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 @@
             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 @@
 
 #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
 }