JeffLIrion / adb_shell

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

Old adb server version (31) is not supported using AdbDeviceTcp #190

Closed Noam5 closed 3 years ago

Noam5 commented 3 years ago

The following snippet crashes when trying to connect to the adb using tcp

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

adbkey = r'path/to/adbkey'

with open(adbkey) as f:
    priv = f.read()
with open(adbkey + '.pub') as f:
     pub = f.read()
signer = PythonRSASigner(pub, priv)

device1 = AdbDeviceTcp('127.0.0.1', 5553, default_transport_timeout_s=9.)
device1.connect(rsa_keys=[signer], auth_timeout_s=0.1)

And this is the traceback that I'm getting:

Traceback (most recent call last):
  File "c:\temp\adbtest.py", line 15, in <module>
    device1.connect(auth_timeout_s=0.1)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 219, in connect
    cmd, arg0, arg1, banner = self._read([constants.AUTH, constants.CNXN], adb_info)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 754, in _read
    cmd, arg0, arg1, data_length, data_checksum = unpack(msg)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_message.py", line 122, in unpack
    raise ValueError('Unable to unpack ADB command. (length={})'.format(len(message)), constants.MESSAGE_FORMAT, message, e)
ValueError: ('Unable to unpack ADB command. (length=0)', b'<6I', b'', error('unpack requires a buffer of 24 bytes'))

After analyzing the protocol and the data that is sent over the ADB protocol, I noticed that the adb library tries to send one type of data (CNXN message) and does not receive any response, while the adb.exe binary sends a different type of message, and receives a response.

Here is how the adb-shell library sends the data (note it does not receive any response) image

This is the adb.exe message (with a response) image

JeffLIrion commented 3 years ago

Please update to the latest version: pip install -U adb-shell

Noam5 commented 3 years ago

Updated to version 0.4.0 and the data that is sent still looks the same

JeffLIrion commented 3 years ago

You should at least get a different exception with the latest version (timeout instead of unpack error).

If you're connected with adb.exe, this package won't be able to connect because only one connection is allowed at a time.

Noam5 commented 3 years ago

I indeed get the timeout error now. But does that mean that I the library could get a response from the server in any way?


Traceback (most recent call last):
  File "adbtest.py", line 14, in <module>
    device1.connect(rsa_keys=[signer], auth_timeout_s=0.1)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 646, in connect
    self._available, self._maxdata = self._io_manager.connect(self._banner, rsa_keys, auth_timeout_s, auth_callback, adb_info)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 199, in connect
    cmd, arg0, maxdata, banner2 = self._read_expected_packet_from_device([constants.AUTH, constants.CNXN], adb_info)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 379, in _read_expected_packet_from_device
    cmd, arg0, arg1, data = self._read_packet_from_device(adb_info)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 457, in _read_packet_from_device
    msg = self._read_bytes_from_device(constants.MESSAGE_SIZE, adb_info)
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\adb_shell\adb_device.py", line 426, in _read_bytes_from_device
    raise exceptions.AdbTimeoutError("Timeout: read {} of {} bytes (transport_timeout_s = {}, read_timeout_s = {})".format(len(data), len(data) + length, adb_info.transport_timeout_s, adb_info.read_timeout_s))
adb_shell.exceptions.AdbTimeoutError: Timeout: read 0 of 24 bytes (transport_timeout_s = 9.0, read_timeout_s = 10.0)
JeffLIrion commented 3 years ago

That's a different question. All I can say is: if the device is unresponsive, it will timeout while trying to read a 24 byte message.

Are you already connected to the device via adb.exe when you try to connect using this package?

Noam5 commented 3 years ago

I am not already connected via adb.exe when trying to connect using the python package... The device is unresponsive because the package tries to send messages that are unknown for the device (Please see the difference between the message that is sent to the message of adb.exe that should get a response)

JeffLIrion commented 3 years ago

Info

From https://android.googlesource.com/platform/system/core/+/dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0/adb/OVERVIEW.TXT#89:

For example, to query the ADB server for its internal version number, the client will do the following:

1. Connect to tcp:localhost:5037
2. Send the string "000Chost:version" to the corresponding socket

...

The server should answer a request with one of the following:

...

3. As a special exception, for 'host:version', a 4-byte hex string corresponding to the server's internal version number

  That third response has since been removed: https://cs.android.com/android/_/android/platform/packages/modules/adb/+/867c71e5114e76b4f64e9f38e1be060fd9ba3a26:OVERVIEW.TXT;bpv=1;bpt=0;drc=2fd69306184634c6d90db3ed3be5349e71dcc471;dlc=f7e359ef5b79e93919aad30e96c3096dbfd36d3c

Discussion

It looks like you're trying to use this package to find the version of the ADB server. I don't know why your port is 5553, but in the example above it's 5037. Regardless, this package connects directly to an Android device. Communicating with an ADB server is not supported.

Noam5 commented 3 years ago

I don't know why your port is 5553, but in the example above it's 5037

Please ignore the confusion between the 2 ports, these are leftovers from 2 different tests I made. In reality I used the correct ports in both cases

Regardless, this package connects directly to an Android device. Communicating with an ADB server is not supported.

I am indeed trying to to connect to a device, but using a TCP connection and not using USB. But for some reason my device does not expect the CNXN packet that the library sends. Maybe due to lack of version compatibility. Eventually I solved the issue using another adb library which does not send the CNXN packet: https://github.com/openatx/adbutils

Perhaps in the future there will be a backwards compatibility with older versions of ADB devices?

JeffLIrion commented 3 years ago

From what I can tell, adbutils uses the adb binary (aka, ADB server) to send its commands.

I think that you are trying to connect to a device using an ADB server. So the server is connected to the device, and you are connected to the server.

This package replaces the ADB server; you connect directly to the device, no "middleman" necessary. The command that you use should be

# replace with your device's IP address
device_ip = "192.168.0.123"

# I think every Android device uses port 5555
device_port = 5555

device1 = AdbDeviceTcp(device_ip, device_port)
device1.connect(rsa_keys=[signer], auth_timeout_s=0.1)
Noam5 commented 3 years ago

Running netstat on the device itself, I got the following output:

netstat -anput Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:5037 0.0.0.0:* LISTEN 492/adbd

Nothing related to adb was listening on any other port

I was not directly accessible to the device, so I used the adb port forwarding:

adb.exe forward tcp:5555 tcp:5037

Then I tried running the snippet you attached. I got the same error adb_shell.exceptions.AdbTimeoutError

So the connection was made directly to the device itself (The server was just forwarding ports), but there was still the same error

JeffLIrion commented 3 years ago

I don't understand why you need to forward the port.

What is the output when you list the devices? I think the command is adb.exe devices.