JeffLIrion / adb_shell

A Python implementation of ADB with shell and FileSync functionality.
Apache License 2.0
543 stars 60 forks source link

get return code of shell command #217

Open le91688 opened 1 year ago

le91688 commented 1 year ago

Currently, adb.shell("my command) returns the result string.

getting the command return code can be achieved by doing something like

adb.shell(my_command; echo exit_code: $?) and parsing the return code out, but would be preferable to have a better mechanism for getting the return code ... possibly like

adb.shell(my_command, ret) where ret is assigned the return code

JeffLIrion commented 1 year ago

I don't think the ADB protocol sends the shell command's return code, so I think your approach is the only way to do it. And I'd rather not wrap every shell command with that and strip off the return code.

awm129 commented 1 year ago

Somehow real adb does this (along with separation of stdout and stderr)

[~]$ adb --version
Android Debug Bridge version 1.0.41
Version 33.0.3-8952118
Installed as /opt/android-platform-tools/platform-tools_r33.0.3/adb
[~]$ adb shell "ls /data/local/tmp" &> /dev/null; echo $?
0
[~]$ adb shell "ls /non/existing/path" &> /dev/null; echo $?
1
JeffLIrion commented 1 year ago

@awm129 could you run those shell commands using this package with debug level logging.

import logging
logging.basicConfig(level=logging.DEBUG)

Maybe that would show where the return codes are transmitted.

awm129 commented 1 year ago

I didn't notice anything obvious in the verbose python logging. But adb definitely separates this info out into the appropriate local output streams and client adb process exit code. You can even suppress separation with the -x option to the shell sub command.

Glancing through the adb source there seems to be a protocol between the on-device adbd and forked shell processes that communicates stdout, stderr, and exit code back to adbd.

Turns out this protocol extends to the wire interface as well. In order to support this, adb_shell would need to either add a new method for adb shell v2 support or change https://github.com/JeffLIrion/adb_shell/blob/a4f2eeb46297fb11a6cc3f553d55339645a4f430/adb_shell/adb_device.py#L842

to something like:

return self._service(b'shell,v2', command.encode('utf8'), transport_timeout_s, read_timeout_s, timeout_s, decode)

And then parse the protocol constants out of the returned bytes and direct the info accordingly. There is probably a way to interrogate a device to see if it supports v2 of the shell command but I didn't dig that far. But I did confirm updating that "shell" string to "shell,v2" indeed returns the proper bytes.