new file mode 100644
@@ -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) {
@@ -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
@@ -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"
`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(-)