Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 275f6c44 authored by Daniel Colascione's avatar Daniel Colascione Committed by android-build-merger
Browse files

Merge "Revert "Revert "Support socket activation of adb server"""

am: a449a1cf

Change-Id: If741b0798e242b8d06eb4bf6dbdb0d059c134306
parents 682c1fc1 a449a1cf
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
adb can be configured to work with systemd-style socket activation,
allowing the daemon to start automatically when the adb control port
is forwarded across a network. You need two files, placed in the usual
systemd service directories (e.g., ~/.config/systemd/user for a user
service).

adb.service:

--- START adb.service CUT HERE ---
[Unit]
Description=adb
After=adb.socket
Requires=adb.socket
[Service]
Type=simple
# FD 3 is part of the systemd interface
ExecStart=/path/to/adb server nodaemon -L acceptfd:3
--- END adb.service CUT HERE ---

--- START adb.socket CUT HERE ---
[Unit]
Description=adb
PartOf=adb.service
[Socket]
ListenStream=127.0.0.1:5037
Accept=no
[Install]
WantedBy=sockets.target
--- END adb.socket CUT HERE ---

After installing the adb service, the adb server will be started
automatically on any connection to 127.0.0.1:5037 (the default adb
control port), even after adb kill-server kills the server.

Other "superserver" launcher systems (like macOS launchd) can be
configured analogously. The important part is that adb be started with
"server" and "nodaemon" command line arguments and that the listen
address (passed to -L) name a file descriptor that's ready to
accept(2) connections and that's already bound to the desired address
and listening. inetd-style pre-accepted sockets do _not_ work in this
configuration: the file descriptor passed to acceptfd must be the
serve socket, not the accepted connection socket.
+1 −1
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ std::optional<std::string> adb_get_server_executable_path() {
    int port;
    std::string error;
    if (!parse_tcp_socket_spec(__adb_server_socket_spec, nullptr, &port, nullptr, &error)) {
        LOG(FATAL) << "failed to parse server socket spec: " << error;
        return {};
    }

    return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb." + std::to_string(port);
+1 −0
Original line number Diff line number Diff line
@@ -107,6 +107,7 @@ static void help() {
        "       localfilesystem:<unix domain socket name>\n"
        "       dev:<character device name>\n"
        "       jdwp:<process pid> (remote only)\n"
        "       acceptfd:<fd> (listen only)\n"
        " forward --remove LOCAL   remove specific forward socket connection\n"
        " forward --remove-all     remove all forward socket connections\n"
        " ppp TTY [PARAMETER...]   run PPP over USB\n"
+47 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include "socket_spec.h"

#include <limits>
#include <string>
#include <string_view>
#include <unordered_map>
@@ -28,10 +29,12 @@
#include <cutils/sockets.h>

#include "adb.h"
#include "adb_utils.h"
#include "sysdeps.h"

using namespace std::string_literals;

using android::base::ConsumePrefix;
using android::base::StringPrintf;

#if defined(__linux__)
@@ -131,7 +134,7 @@ bool is_socket_spec(std::string_view spec) {
            return true;
        }
    }
    return spec.starts_with("tcp:");
    return spec.starts_with("tcp:") || spec.starts_with("acceptfd:");
}

bool is_local_socket_spec(std::string_view spec) {
@@ -235,6 +238,9 @@ bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std
        *error = "vsock is only supported on linux";
        return false;
#endif  // ADB_LINUX
    } else if (address.starts_with("acceptfd:")) {
        *error = "cannot connect to acceptfd";
        return false;
    }

    for (const auto& it : kLocalSocketTypes) {
@@ -334,6 +340,46 @@ int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_
        *error = "vsock is only supported on linux";
        return -1;
#endif  // ADB_LINUX
    } else if (ConsumePrefix(&spec, "acceptfd:")) {
#if ADB_WINDOWS
        *error = "socket activation not supported under Windows";
        return -1;
#else
        // We inherited the socket from some kind of launcher. It's already bound and
        // listening. Return a copy of the FD instead of the FD itself so we implement the
        // normal "listen" contract and can succeed more than once.
        unsigned int fd_u;
        if (!ParseUint(&fd_u, spec) || fd_u > std::numeric_limits<int>::max()) {
            *error = "invalid fd";
            return -1;
        }
        int fd = static_cast<int>(fd_u);
        int flags = get_fd_flags(fd);
        if (flags < 0) {
            *error = android::base::StringPrintf("could not get flags of inherited fd %d: '%s'", fd,
                                                 strerror(errno));
            return -1;
        }
        if (flags & FD_CLOEXEC) {
            *error = android::base::StringPrintf("fd %d was not inherited from parent", fd);
            return -1;
        }

        int dummy_sock_type;
        socklen_t dummy_sock_type_size = sizeof(dummy_sock_type);
        if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &dummy_sock_type, &dummy_sock_type_size)) {
            *error = android::base::StringPrintf("fd %d does not refer to a socket", fd);
            return -1;
        }

        int new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
        if (new_fd < 0) {
            *error = android::base::StringPrintf("could not dup inherited fd %d: '%s'", fd,
                                                 strerror(errno));
            return -1;
        }
        return new_fd;
#endif
    }

    for (const auto& it : kLocalSocketTypes) {
+8 −1
Original line number Diff line number Diff line
@@ -349,8 +349,15 @@ static __inline__ bool adb_is_separator(char c) {
    return c == '/';
}

static __inline__ int get_fd_flags(borrowed_fd fd) {
    return fcntl(fd.get(), F_GETFD);
}

static __inline__ void close_on_exec(borrowed_fd fd) {
    fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
    int flags = get_fd_flags(fd);
    if (flags >= 0 && (flags & FD_CLOEXEC) == 0) {
        fcntl(fd.get(), F_SETFD, flags | FD_CLOEXEC);
    }
}

// Open a file and return a file descriptor that may be used with unix_read(),