14

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.

  • you may refer to https://github.com/termux/termux-app/issues/77 – Amit Kumar Khare Nov 10 '17 at 10:12
  • Thanks for link. However, I think that link is actually trying to do the opposite of what I want: emulate the behavior of termux from adb. I actually want to emulate the behavior of commands run from `adb shell` in a shell running locally on the device. My confusion is that I am running the same binary using the same shell binary on the same device and getting a different output (technically no output when run locally). –  Nov 12 '17 at 06:04

5 Answers5

6

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:

  • the -i flag is used to start with an empty environment
  • USER=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 prefer
  • shell 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 shell

Another 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
Six
  • 5,122
  • 3
  • 29
  • 38
  • Thanks for the detailed response. I didn't know about some of these settings/commands. I am using Magisk for root, but root seems to be working correctly. Unfortunately, this command still gives me the same result, at least for the "cmd" command. It just returns nothing. I tried on a Nexus 5x running Nougat to make sure it wasn't the device, and same result: works in `adb shell`, null in Termux with your command. Must be a change introduced in Nougat? –  Dec 06 '17 at 00:45
  • 1
    Worked for me on Pie. – divykj Oct 24 '18 at 05:34
  • 1
    Thank you so much! Exactly what I was looking for! ADB commands worked on Samsung Edge S6 Android 7.0 Nougat with Termux! – idontknow Jul 25 '20 at 03:29
6

The problem is Termux. By design, Termux runs only (or is mostly?) the Linux command line programs that you install from within Termux using apt or the newer "native" package management interface, e.g. apt install bsdtar. What you need to run the adb shell commands is a terminal emulator that can truly access the underlying Android file system, not just the Termux that is practically a chroot save for the fact that it's aware it's not running commands from the filesystem root /.

As a simple test, run the following command:

    which ls

It should return something like /system/bin/ls. But if it returns something like /data/data/com.termux/files/usr/bin/applets/ls then you have to change your terminal emulator to something else. I suspect that Termux was designed to take into account the more restrictive shell execution policies that Google put into place after KitKat or the Android 4.X.

The Android distribution I'm using, LineageOS 14.1, comes with a built-in shell emulator that allows me to run commands found in /system/bin/ls.

4

So I tried this recently...if you're rooted you can use a terminal emulator.

  • su
  • then the command you want without "adb shell" part of it.

i tried the command "adb shell dumpsys deviceidle force-idle" in order to force device into doze. I did this on the device via terminal emulator as: "dumpsys deviceidle force-idle" and it did take effect. also the dumpsys batterystats command worked.

be careful with commands with extensive text output, as the screen will be flooded with the output and will be unresponsive for some time.

Aravinda P
  • 41
  • 1
0

EDIT I originally answered this without the termux tag in mind. This worked for me while trying to execute shell commands on a vanilla emulator and saw this question while researching, so I tried to answer it differently.

You almost had it there in your question. You only need to execute sh:

int result = -1;
try {
    final Process shell = Runtime.getRuntime().exec("sh");
    final DataOutputStream commands = new DataOutputStream(shell.getOutputStream());
    commands.writeBytes("write a series");
    commands.writeBytes("of commands here");
    commands.writeBytes("exit\n");
    commands.flush();
    result = shell.waitFor();
  }
} catch (Exception e) {
  e.printStackTrace();
}

If result == 0 the commands were succesful, else otherwise

E_net4
  • 27,810
  • 13
  • 101
  • 139
Chisko
  • 3,092
  • 6
  • 27
  • 45
  • It tells me no device it attached (nor does it find any devices). Would you know why? – Edw590 Jan 06 '20 at 23:03
  • @DADi590 I assume your device does not have USB debugging enabled – Chisko Jan 06 '20 at 23:33
  • @Chrisko It does though. That's why I didn't understand why it didn't work. – Edw590 Jan 07 '20 at 21:30
  • @DADi590 if `adb devices` doesn't give you anything, there's a bunch of answers you can go through: https://stackoverflow.com/questions/15721778/adb-no-devices-found – Chisko Jan 07 '20 at 22:51
  • Ah but it works on PC. Just not on the emulator. I'll search a bit deeper about it then. Thanks – Edw590 Jan 09 '20 at 09:50
-2
  • Only rooted android
  • Busybox must be installed (though you can try without it)

Just write the normal command without the prefix adb

Alexey Usharovski
  • 1,404
  • 13
  • 31