diff mbox series

[meta-oe,04/10] android-tools: adbd: restart after adb root/unroot

Message ID 20261110-android-tools-adbd-v1-4-cc2176f381c3@gmail.com
State New
Headers show
Series android-tools: adbd fixes and opt-in access control for Linux systems | expand

Commit Message

Alex Kiernan Nov. 10, 2026, 5:35 p.m. UTC
`adb root` and `adb unroot` write the new privilege state to
/run/adbd.root and expect adbd to be restarted to apply it, as Android's
init does. Nothing restarted it here, so the client's wait-for-disconnect
hung and adbd kept its uid. Have adbd exit after writing the state, and
restart the service on any exit, not only on failure.

AI-Generated: Claude Opus 5.5 (Claude Code)
Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
---
 ...exit-after-adb-root-unroot-so-an-init-sup.patch | 60 ++++++++++++++++++++++
 .../android-tools/android-tools-adbd.service       |  2 +-
 .../android-tools/android-tools_35.0.2.bb          |  1 +
 3 files changed, 62 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/meta-oe/recipes-devtools/android-tools/android-tools/0019-adb-daemon-exit-after-adb-root-unroot-so-an-init-sup.patch b/meta-oe/recipes-devtools/android-tools/android-tools/0019-adb-daemon-exit-after-adb-root-unroot-so-an-init-sup.patch
new file mode 100644
index 000000000000..a55e4259194c
--- /dev/null
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/0019-adb-daemon-exit-after-adb-root-unroot-so-an-init-sup.patch
@@ -0,0 +1,60 @@ 
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Alex Kiernan <alex.kiernan@gmail.com>
+Date: Sun, 19 Jul 2026 08:59:06 +0100
+Subject: [PATCH] adb: daemon: exit after adb root/unroot so an init supervisor
+ restarts adbd
+
+On Android, `adb root`/`adb unroot` write the desired privilege state and
+rely on init restarting adbd (via a property trigger) to pick it up. This
+Linux port keeps the "write state file, rely on a restart" model but the
+running adbd never exits, so on a non-Android system with nothing watching
+the state file the daemon keeps its current uid and the client's
+`wait-for-disconnect` hangs (or times out once the USB transport happens to
+drop for unrelated reasons).
+
+Exit after successfully writing the root state, as the classic adbd did,
+so the service manager restarts adbd (systemd with Restart=always, or a
+supervisor such as runit); on restart should_drop_privileges() reads the
+state file and comes back root (root) or drops to the adb user (unroot). A
+short delay lets the reply reach the host over USB before the gadget is
+torn down.
+
+Upstream-Status: Pending
+Signed-off-by: Alex Kiernan <alex.kiernan@gmail.com>
+---
+ packages/modules/adb/daemon/restart_service.cpp | 15 ++++++++++++++-
+ 1 file changed, 14 insertions(+), 1 deletion(-)
+
+diff --git a/packages/modules/adb/daemon/restart_service.cpp b/packages/modules/adb/daemon/restart_service.cpp
+index 8aee1afeaef8..3c3fd24ed5af 100644
+--- a/packages/modules/adb/daemon/restart_service.cpp
++++ b/packages/modules/adb/daemon/restart_service.cpp
+@@ -65,7 +65,16 @@ void restart_root_service(unique_fd fd) {
+         if (write_root_state(kRootMagic, kRootMagicSize)) {
+             LOG(INFO) << "adbd restarting as root";
+             WriteFdExactly(fd.get(), "restarting adbd as root\n");
+-            return;
++            // Unlike on Android (where init restarts adbd on a property
++            // trigger), on this Linux port nothing watches the root-state
++            // file, so a still-running adbd would keep its current uid and
++            // the client's `wait-for-disconnect` would hang. Exit instead so
++            // the init supervisor restarts us; on restart should_drop_
++            // privileges() reads #ROOT# and we come back as root. Give the
++            // reply time to reach the host over USB before tearing the gadget
++            // down, as the classic adbd did.
++            sleep(1);
++            _exit(0);
+         }
+         usleep(100000);
+     }
+@@ -84,6 +93,10 @@ void restart_unroot_service(unique_fd fd) {
+     }
+     LOG(INFO) << "adbd restarting as nonroot";
+     WriteFdExactly(fd.get(), "restarting adbd as non root\n");
++    // See restart_root_service(): exit so the init supervisor restarts adbd,
++    // which then reads #NOROOT# and drops privileges again.
++    sleep(1);
++    _exit(0);
+ }
+ 
+ void restart_tcp_service(unique_fd fd, int port) {
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
index 7c16b5cea20f..355d91517cff 100644
--- a/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
+++ b/meta-oe/recipes-devtools/android-tools/android-tools/android-tools-adbd.service
@@ -5,7 +5,7 @@  Before=android-system.service
 
 [Service]
 Type=notify
-Restart=on-failure
+Restart=always
 ExecStartPre=-/usr/bin/android-gadget-setup adb
 ExecStart=/usr/bin/adbd
 
diff --git a/meta-oe/recipes-devtools/android-tools/android-tools_35.0.2.bb b/meta-oe/recipes-devtools/android-tools/android-tools_35.0.2.bb
index 9a0bae98dd19..e247cbbafa60 100644
--- a/meta-oe/recipes-devtools/android-tools/android-tools_35.0.2.bb
+++ b/meta-oe/recipes-devtools/android-tools/android-tools_35.0.2.bb
@@ -63,6 +63,7 @@  SRC_URI = "https://deb.debian.org/debian/pool/main/a/android-platform-tools/andr
            file://0016-adbd-forward-the-reboot-target-to-RESTART2.patch \
            file://0017-adbd-shell-start-in-HOME-and-drop-the-Android-only-T.patch \
            file://0018-adbd-do-not-use-pthread_kill-as-a-thread-liveness-pr.patch \
+           file://0019-adb-daemon-exit-after-adb-root-unroot-so-an-init-sup.patch \
            "
 
 SRC_URI[orig.md5sum] = "352376965cdef7bd7505d8fefdd43d50"