Remote-drive Termux on any Android device over plain adb — no root, no
extra app, no SSH. A few tiny pieces:
| piece | where | what |
|---|---|---|
ax |
device Termux $PREFIX/bin/ax |
environment normalizer executed via run-as |
atx |
host $PREFIX/bin (or anywhere) |
thin wrapper that re-quotes arguments for the device shell |
usb-host |
host | make the host the USB OTG controller and attach the peer (Android-to-Android adb) |
usb-device |
host | revert the host to gadget mode so a PC can debug it |
./install.sh # push ax to the device + install atx locally
usb-host # Android host: take the OTG host role, list the peer
atx # interactive login bash on the device
atx pkg update # single command
atx bash -c 'apt list --upgradable | wc -l'
ATX_PACKAGE=com.termux.debug atx ... # different package
ANDROID_SERIAL=xxx atx ... # multi-deviceWhen the host is itself an Android device (Termux) wired to the target
through a USB-C cable, run usb-host once after plugging in: it flips the
host's USB controller to the host role and connects over adb. usb-device
reverts to gadget mode so a PC can debug the host again.
Both are vendored as-is from a daily-driver setup: they write the MTK
usb-role sysfs node (/sys/devices/platform/soc/11201000.usb0/...) and the
Type-C preferred_role, and need Termux sudo (tsu). Adjust RS/TC if
your host exposes different paths. Note: run usb-host when the host is in
its default device mode (e.g. after usb-device or a reboot) — re-running
it while already in host mode resets the controller and may drop the peer's
USB function set.
host shell ──> adb shell ──> run-as com.termux files/usr/bin/ax CMD
│
ax: cd $HOME, umask 077, PATH=$PREFIX/bin,
env -i {HOME,PREFIX,PATH,TMPDIR,LANG,LD_PRELOAD}, exec "$@"
run-as works because official Termux builds are marked debuggable; it runs
your command as the Termux app uid (same data dir, same SELinux MCS
categories), which is why apt/dpkg state, files and credentials behave exactly
like a local session.
The same probe (probe/axprobe.sh) was executed
- through
atx(SELinuxrunas_app), and - inside the real Termux app (
untrusted_app_27) via Termux'sRUN_COMMANDintent (needsallow-external-apps=truein~/.termux/termux.propertiesand a root-flavouredam startserviceto satisfy the permission check).
Raw outputs are kept in probe/runas-side.out and probe/app-side.out.
- uid/gid, app-data isolation (same MCS categories)
- bash / apt / dpkg / pkg toolchain resolution and dpkg state
- file rwx + script execution under
$HOMEand$PREFIX - DNS and outbound HTTPS
- binder calls that an unprivileged app may make (
pm path,settings get,/system/bin/am ...) - signals, fd limits,
getprop
| symptom | fix |
|---|---|
starting cwd was the package dir, not $HOME |
cd "$HOME" |
/system/bin leaked into PATH (toybox wget shadowed) |
PATH=$PREFIX/bin only |
| umask 0000 → world-readable files | umask 077 |
adb-injected env (ANDROID_*, HOSTNAME, ANDROID_SOCKET_adbd, …) |
env -i rebuild |
- SELinux domain
runas_appvsuntrusted_app_27; supplementary groups differ (the run-as context carries shell-ish groups such asreadproc, i.e. it is a small superset of the real app). - Seccomp off in the run-as context (the app is filtered); capability bounding set differs.
- No tty: no job control,
isatty()false, interactive TUIs unusable. - No app session:
TERMUX_APP__*/TERMUX_VERSION/TERMunset;$PREFIX/bin/am(Termux's am-socket wrapper) andtermux-*app-integrated commands need a live Termux session. Workaround: use/system/bin/am(orsu -c amfor privileged operations) — both verified to behave identically from either context. - Scoped storage:
/sdcardwrites fail in both contexts unless the Termux app itself has been granted storage permission (then the real app can write, the run-as context still cannot).
Bottom line: for CLI work — package management, builds, scripting,
networking, file operations — atx is a faithful drop-in for typing in the
Termux app.
ax device-side helper (installed as $PREFIX/bin/ax)
atx host-side wrapper
usb-host host-side: switch to USB host role (Android↔Android adb)
usb-device host-side: revert to USB device role
install.sh installer (device + host)
probe/axprobe.sh environment equivalence probe
probe/*.out reference outputs from the verification run
LICENSE MIT
MIT — see LICENSE.