From a shell on my PC, I can run adb shell cmd package list packages
, and get a list of all installed packages. I would like to run this and similar commands locally on my Android phone (Nexus 6P) in a terminal emulator (currently using Termux).
If I open the same shell with /system/bin/sh
, and then try to run /system/bin/cmd package list packages
, nothing happens (no errors, just outputs nothing and reloads the prompt).
If I run /system/bin/cmd -l
the list of options appears as expected. $PATH
and $LD_LIBRARY_PATH
are the same in both environments. One major difference is that echo $USER
returns "shell" from adb shell
, but returns my local username from /system/bin/sh
launched from Termux.
Is there any way to replicate the behavior of commands run from adb shell
in a terminal emulator locally on Android?
Edit: My device is rooted, and I am OK with root only solutions.
I don't have a rooted Nougat device handy, but something like the following may be a close enough approximation to adb shell
(assuming you are using SuperSU):
env -i USER=shell "$(PATH=/system/xbin:/system/bin:/su/bin:/sbin:/magisk/.core/bin which su)" shell --context u:r:shell:s0 --shell /system/bin/sh --command COMMAND
I (very briefly) tested it from Termux on a rooted Marshmallow device.
To elaborate:
-i
flag is used to start with an empty environmentUSER=shell
isn't specifically required, but for some reason su
refuses to run with a completely empty environment$(PATH=/system/xbin:/system/bin:/su/bin:/sbin:/magisk/.core/bin which su)
points to the full path of the su binary on your device and can be hardcoded if you prefershell
instructs the su
binary to login as the shell user (the same as adb shell
)--context u:r:shell:s0
sets the appropriate SELinux context--shell /system/bin/sh
instructs SuperSU to use the system shell rather than it's own sush
shellAnother option would be to actually run adb from the device, connecting to itself over TCP. If you need some functionality that is only available via adb (e.g. in my case it was adb forward
) then this may be your only option. Unfortunately this isn't particularly convenient.
I wasn't able to find success with any publicly available adb binaries, so I build it myself with a few minor changes. You can see the sources I used and the changes I made at https://github.com/shakalaca/fastboot-adb-android and https://github.com/brbsix/fastboot-adb-android, respectively.
Once you have adb installed, here's an abbreviated list of commands I used to connect to the device:
# Add iptables rules to block external connections to port 9999'
su root iptables -N adbd
su root iptables -A adbd -i lo -p tcp -m tcp --dport 9999 -j ACCEPT
su root iptables -A adbd -p tcp -m tcp --dport 9999 -j DROP
su root iptables -A INPUT -j adbd
# Necessary in order to display authorization prompt
su shell setprop ro.debuggable 1
su shell setprop service.adb.tcp.port 9999
su root start adbd
adb connect 127.0.0.1:9999
adb wait-for-local-device
To shut down:
adb kill-server
su root stop adbd
su shell setprop ro.debuggable 0
su shell setprop service.adb.tcp.port 0
su root iptables -D INPUT -j adbd
su root iptables -F adbd
su root iptables -X adbd