adb_shell icon indicating copy to clipboard operation
adb_shell copied to clipboard

adb_shell.exceptions.InvalidCommandError in `connect()` with Android emulator

Open mal-mel opened this issue 5 years ago • 35 comments

Hello, Jeff, i need help) When i running my code:

from adb_shell import adb_device
from adb_shell.auth.sign_pythonrsa import PythonRSASigner
import os


class Controller:
    def __init__(self, host: str, port: int):
        self.host, self.port = host, port
        self.device, self._signer = None, None

    def connect_to_device(self, timeout: int):
        self.device = adb_device.AdbDeviceTcp(self.host, self.port, default_timeout_s=timeout)
        self._make_sign("~/.android/adbkey")
        self.device.connect(auth_timeout_s=0.1, rsa_keys=[self._signer])

    def _make_sign(self, path: str):
        with open(os.path.expanduser(path)) as file:
            rsa_key = file.read()
        self._signer = PythonRSASigner("", rsa_key)

    def shell(self, command: str) -> str:
        output = self.device.shell(command, decode=True)
        return output


if __name__ == '__main__':
    adb_controller = Controller("localhost", 5556)
    adb_controller.connect_to_device(timeout=10)
    print(adb_controller.shell("echo work!"))

An emulator is running on 5556 port. I get an error adb_shell.exceptions.InvalidCommandError: ('Unknown command: 72646e41', 1919184449, (543451503, 1936617283)) or something like this, I would like to know why this is happening.

mal-mel avatar Feb 28 '20 15:02 mal-mel

def from_int(n):
    return ''.join(chr((n >> (i * 8)) % 256) for i in range(4)).encode('utf-8')

That is the opposite of https://github.com/JeffLIrion/adb_shell/blob/825294d9a4923b8857380b6b5b51a8937e91aa70/tests/test_adb_device.py#L25-L26

I don't know what 72646e41 is, but the following 3 numbers translate to Andr + oid + Cons.

Your exception is occurring here: https://github.com/JeffLIrion/adb_shell/blob/825294d9a4923b8857380b6b5b51a8937e91aa70/adb_shell/adb_device.py#L847

If you want more info, you need to turn on debug logging.

JeffLIrion avatar Feb 29 '20 02:02 JeffLIrion

Ok, but how do I make it work?)

mal-mel avatar Feb 29 '20 12:02 mal-mel

More info is needed to see what's going on.

import logging

logging.getLogger().setLevel(logging.DEBUG)

Post a log and I'll take a look.

JeffLIrion avatar Feb 29 '20 13:02 JeffLIrion

2020-02-29 16:25:44,905 : [adb_device.py.921]: DEBUG : bulk_write: b'CNXN\x00\x00\x00\x01\x00\x10\x00\x00\x13\x00\x00\x00c\x05\x00\x00\xbc\xb1\xa7\xb1'
2020-02-29 16:25:44,905 : [adb_device.py.923]: DEBUG : bulk_write: b'host::9da23738bc43\x00'
2020-02-29 16:25:44,906 : [adb_device.py.784]: DEBUG : bulk_read(24): b'Android Console: Authent'

mal-mel avatar Feb 29 '20 13:02 mal-mel

Try this with debug logging enabled and post a log.

adb_controller = Controller("localhost", 5556)
try:
    adb_controller.connect_to_device(timeout=10)
except:
    pass
print(adb_controller.device._handle.bulk_read(1000, 5))

JeffLIrion avatar Feb 29 '20 14:02 JeffLIrion

This is output:

b"ication required\r\nAndroid Console: type 'auth <auth_token>' to authenticate\r\nAndroid Console: you can find your <auth_token> in \r\n'/root/.emulator_console_auth_token'\r\nOK\r\n"
Traceback (most recent call last):
  File "test.py", line 62, in <module>
    print(adb_controller.shell("echo work!"))
  File "test.py", line 26, in shell
    output = self.device.shell(command, decode=True)
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/adb_device.py", line 426, in shell
    return self._service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode)
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/adb_device.py", line 402, in _service
    return b''.join(self._streaming_command(service, command, adb_info)).decode('utf8')
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/adb_device.py", line 953, in _streaming_command
    self._open(b'%s:%s' % (service, command), adb_info)
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/adb_device.py", line 738, in _open
    _, adb_info.remote_id, their_local_id, _ = self._read([constants.OKAY], adb_info)
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/adb_device.py", line 783, in _read
    msg = self._handle.bulk_read(constants.MESSAGE_SIZE, adb_info.timeout_s)
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/handle/tcp_handle.py", line 127, in bulk_read
    raise TcpTimeoutException(msg)
adb_shell.exceptions.TcpTimeoutException: Reading from localhost:5556 timed out (10 seconds)

Log:

2020-02-29 18:21:50,678 : [adb_device.py.921]: DEBUG : bulk_write: b'CNXN\x00\x00\x00\x01\x00\x10\x00\x00\x13\x00\x00\x00c\x05\x00\x00\xbc\xb1\xa7\xb1'
2020-02-29 18:21:50,684 : [adb_device.py.923]: DEBUG : bulk_write: b'host::9da23738bc43\x00'
2020-02-29 18:21:50,685 : [adb_device.py.784]: DEBUG : bulk_read(24): b'Android Console: Authent'
2020-02-29 18:21:50,685 : [adb_device.py.921]: DEBUG : bulk_write: b'OPEN\x01\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\xf5\x05\x00\x00\xb0\xaf\xba\xb1'
2020-02-29 18:21:50,685 : [adb_device.py.923]: DEBUG : bulk_write: b'shell:echo work!\x00'

mal-mel avatar Feb 29 '20 15:02 mal-mel

That output is not from the same code I posted.

JeffLIrion avatar Feb 29 '20 15:02 JeffLIrion

Ok, i commented print(adb_controller.shell("echo work!")) output:

b"ication required\r\nAndroid Console: type 'auth <auth_token>' to authenticate\r\nAndroid Console: you can find your <auth_token> in \r\n'/root/.emulator_console_auth_token'\r\nOK\r\n"

mal-mel avatar Feb 29 '20 15:02 mal-mel

OK, I see now.

It looks like it's saying that it will only work if you use the key /root/.emulator_console_auth_token.

This is the reply you get when you try to connect:

Android Console: Authentication required
Android Console: type 'auth <auth_token>' to authenticate
Android Console: you can find your <auth_token> in 
'/root/.emulator_console_auth_token'
OK

Have you connected to the emulator using the official ADB binary?

JeffLIrion avatar Feb 29 '20 15:02 JeffLIrion

Yes, the official adb connect to emulator successfully

mal-mel avatar Feb 29 '20 16:02 mal-mel

Do you have a file /root/.emulator_console_auth_token?

If so, try using that in your connect_to_device function.

JeffLIrion avatar Feb 29 '20 16:02 JeffLIrion

Have you had a chance to try using the key /root/.emulator_console_auth_token (if it exists)?

JeffLIrion avatar Mar 01 '20 14:03 JeffLIrion

Hello, Jeff, sorry for the silence, there was no access to the computer Yes, i have /root/.emulator_console_auth_token. Should I use it instead of ~ / .android / adbkey?

mal-mel avatar Mar 02 '20 10:03 mal-mel

If i connect to Android console manually and enter auth <my_token> all work fine (i have access to the Android Console, but my goal is android shell). How i to do this with your lib?

mal-mel avatar Mar 02 '20 10:03 mal-mel

Hello, Jeff, sorry for the silence, there was no access to the computer Yes, i have /root/.emulator_console_auth_token. Should I use it instead of ~ / .android / adbkey?

Yes, please try that.

JeffLIrion avatar Mar 02 '20 13:03 JeffLIrion

Yes, I tried to make a signature with this key, but nothing

mal-mel avatar Mar 02 '20 13:03 mal-mel

Can you post the output from this, as you did before.

adb_controller = Controller("localhost", 5556)
try:
    adb_controller.connect_to_device(timeout=10)
except:
    pass
print(adb_controller.device._handle.bulk_read(1000, 5))

JeffLIrion avatar Mar 02 '20 14:03 JeffLIrion

Traceback (most recent call last):
  File "test.py", line 36, in <module>
    print(adb_controller.device._handle.bulk_read(1000, 5))
  File "/usr/local/lib/python3.6/dist-packages/adb_shell/handle/tcp_handle.py", line 122, in bulk_read
    readable, _, _ = select.select([self._connection], [], [], timeout)
TypeError: argument must be an int, or have a fileno() method.

mal-mel avatar Mar 02 '20 15:03 mal-mel

I need debug logs to see the data that's being sent and read.

import logging
import os

from adb_shell import adb_device
from adb_shell.auth.sign_pythonrsa import PythonRSASigner


logging.getLogger().setLevel(logging.DEBUG)


class Controller:
    def __init__(self, host: str, port: int):
        self.host, self.port = host, port
        self.device, self._signer = None, None

    def connect_to_device(self, timeout: int):
        self.device = adb_device.AdbDeviceTcp(self.host, self.port, default_timeout_s=timeout)
        self._make_sign("/root/.emulator_console_auth_token")
        self.device.connect(auth_timeout_s=0.1, rsa_keys=[self._signer])

    def _make_sign(self, path: str):
        with open(os.path.expanduser(path)) as file:
            rsa_key = file.read()
        self._signer = PythonRSASigner("", rsa_key)

    def shell(self, command: str) -> str:
        output = self.device.shell(command, decode=True)
        return output


if __name__ == '__main__':
    adb_controller = Controller("localhost", 5556)
    try:
        adb_controller.connect_to_device(timeout=10)
    except:
        pass
    print(adb_controller.device._handle.bulk_read(1000, 5))

JeffLIrion avatar Mar 02 '20 15:03 JeffLIrion

I met the same problem after i ctrl+c a running "shell command".

print device1.shell('busybox ping www.baidu.com', timeout_s=10, total_timeout_s=10) Traceback (most recent call last): File "", line 1, in File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 460, in shell return self._service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 404, in _service return b''.join(self._streaming_command(service, command, adb_info)).decode('utf8') File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 1013, in _streaming_command for data in self._read_until_close(adb_info): File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 955, in _read_until_close cmd, data = self._read_until([constants.CLSE, constants.WRTE], adb_info) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 908, in _read_until cmd, remote_id2, local_id2, data = self._read(expected_cmds, adb_info) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 841, in _read msg = self._handle.bulk_read(constants.MESSAGE_SIZE, adb_info.timeout_s) File "C:\Python27\lib\site-packages\adb_shell\handle\tcp_handle.py", line 122, in bulk_read readable, _, _ = select.select([self._connection], [], [], timeout) KeyboardInterrupt print device1.shell('busybox ping www.baidu.com') Traceback (most recent call last): File "", line 1, in File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 460, in shell return self._service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 404, in _service return b''.join(self._streaming_command(service, command, adb_info)).decode('utf8') File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 1011, in _streaming_command self._open(b'%s:%s' % (service, command), adb_info) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 796, in _open _, adb_info.remote_id, their_local_id, _ = self._read([constants.OKAY], adb_info) File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 847, in _read raise exceptions.InvalidCommandError('Unknown command: %x' % cmd, cmd, (arg0, arg1)) adb_shell.exceptions.InvalidCommandError: ('Unknown command: 62203436', 1646277686, (1936028793, 1869768224))

I also noticed the timeout seems notworking. Following command stuck all the time: print device1.shell('busybox ping www.baidu.com', timeout_s=10, total_timeout_s=10)

kunzhipeng avatar Apr 22 '20 13:04 kunzhipeng

I can reproduce the "adb_shell.exceptions.InvalidCommandError" problem like following:

Run: print device1.shell('busybox ping www.baidu.com') Press “Ctrl + C”, then run: print device1.shell('echo hi')

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 460, in shell
    return self._service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode)
  File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 404, in _service
    return b''.join(self._streaming_command(service, command, adb_info)).decode('utf8')
  File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 1011, in _streaming_command
    self._open(b'%s:%s' % (service, command), adb_info)
  File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 796, in _open
    _, adb_info.remote_id, their_local_id, _ = self._read([constants.OKAY], adb_info)
  File "C:\Python27\lib\site-packages\adb_shell\adb_device.py", line 847, in _read
    raise exceptions.InvalidCommandError('Unknown command: %x' % cmd, cmd, (arg0, arg1))
adb_shell.exceptions.InvalidCommandError: ('Unknown command: 62203436', 1646277686, (1936028793, 1869768224))

kunzhipeng avatar Apr 22 '20 13:04 kunzhipeng

@kunzhipeng your issue is different. I changed the title of this issue to reflect that it is about an error when trying to connect to an Android emulator.

I think the Ctrl+C issue you're describing here is even different than the new issue you created. I think the problem is that you're stopping the current task on the host computer -- i.e., running that she'll command via adb_shell in Python -- but one or both of the following scenarios occurs:

  • the command you sent is still running on the Android device
  • the command has stopped on the Android device, but there is still more output from that command for adb_shell to read

Either way, when you try to run a new shell command, it expects a response to the new command but receives a response from the old command, hence the error.

I'm not sure how to handle that other than closing the connection and reconnecting.

JeffLIrion avatar Apr 22 '20 15:04 JeffLIrion

Glad that I'm facing the exactly same issue here. I'm using Mac OS X Cata...blah, and using good old telnet I was able to do somethings, but facing InvalidCommandError: ('Unknown command: 72646e41', 1919184449, (543451503, 1936617283)).

combacsa avatar May 09 '20 15:05 combacsa

I replaced this line self._make_sign("/Users/khbyun/.android/adbkey") and debugging log I got is:

b"ication required\r\nAndroid Console: type 'auth <auth_token>' to authenticate\r\nAndroid Console: you can find your <auth_token> in \r\n'/Users/khbyun/.emulator_console_auth_token'\r\nOK\r\n"

combacsa avatar May 09 '20 15:05 combacsa

So @JeffLIrion is the above log message enough for you to debug?

combacsa avatar May 09 '20 15:05 combacsa

@combacsa try using the key /Users/khbyun/.emulator_console_auth_token, if it exists.

JeffLIrion avatar May 09 '20 16:05 JeffLIrion

@JeffLIrion I tried with it but it failed with error, like it's not a permitable file for a RSA... exact log message is:

combacsa avatar May 09 '20 16:05 combacsa

ValueError: No PEM start marker "b'-----BEGIN PRIVATE KEY-----'" found

combacsa avatar May 09 '20 16:05 combacsa

(I'm kinda in a hurry, since I'm creating a code for a birthday present now...)

combacsa avatar May 09 '20 16:05 combacsa

Interestingly, when I just use telnet, My workflow goes like this:

Command: telnet localhost 5554

Output:

Trying ::1...
Connected to localhost.
Escape character is '^]'.
Android Console: Authentication required
Android Console: type 'auth <auth_token>' to authenticate
Android Console: you can find your <auth_token> in
'/Users/khbyun/.emulator_console_auth_token'
OK

Then I just type the contents from '/Users/khbyun/.emulator_console_auth_token' like

auth <BLAHBLAH>

then

Android Console: type 'help' for a list of commands
OK

So, there could be a sudden change happend in adb's socket protocol?

combacsa avatar May 09 '20 16:05 combacsa