Skip to content

Commit

Permalink
Merge c15eeab into 3b3d23f
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffLIrion committed Dec 12, 2020
2 parents 3b3d23f + c15eeab commit 21d4ebb
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 97 deletions.
75 changes: 58 additions & 17 deletions adb_shell/adb_device.py
Expand Up @@ -89,9 +89,13 @@ class AdbDevice(object):
----------
transport : BaseTransport
A user-provided transport for communicating with the device; must be an instance of a subclass of :class:`~adb_shell.transport.base_transport.BaseTransport`
default_transport_timeout_s : float, None
TODO
banner : str, bytes, None
The hostname of the machine where the Python interpreter is currently running; if
it is not provided, it will be determined via ``socket.gethostname()``
default_transport_timeout_s : float, None
Default timeout in seconds for transport packets, or ``None``
Raises
------
Expand All @@ -104,14 +108,16 @@ class AdbDevice(object):
Whether an ADB connection to the device has been established
_banner : bytearray, bytes
The hostname of the machine where the Python interpreter is currently running
_default_transport_timeout_s : float, None
TODO
_maxdata: int
Maximum amount of data in an ADB packet
_transport : BaseTransport
The transport that is used to connect to the device; must be a subclass of :class:`~adb_shell.transport.base_transport.BaseTransport`
"""

def __init__(self, transport, banner=None):
def __init__(self, transport, default_transport_timeout_s=None, banner=None):
if banner and not isinstance(banner, (bytes, bytearray)):
self._banner = bytearray(banner, 'utf-8')
else:
Expand All @@ -123,8 +129,26 @@ def __init__(self, transport, banner=None):
self._transport = transport

self._available = False
self._default_transport_timeout_s = default_transport_timeout_s
self._maxdata = constants.MAX_PUSH_DATA

# ======================================================================= #
# #
# Properties & simple methods #
# #
# ======================================================================= #
@property
def available(self):
"""Whether or not an ADB connection to the device has been established.
Returns
-------
bool
``self._available``
"""
return self._available

@property
def max_chunk_size(self):
"""Maximum chunk size for filesync operations
Expand All @@ -137,18 +161,27 @@ def max_chunk_size(self):
"""
return min(constants.MAX_CHUNK_SIZE, self._maxdata // 2) or constants.MAX_PUSH_DATA

@property
def available(self):
"""Whether or not an ADB connection to the device has been established.
def _get_transport_timeout_s(self, transport_timeout_s):
"""Use the provided ``transport_timeout_s`` if it is not ``None``; otherwise, use ``self._default_transport_timeout_s``
Parameters
----------
transport_timeout_s : float, None
The potential transport timeout
Returns
-------
bool
``self._available``
float
``transport_timeout_s`` if it is not ``None``; otherwise, ``self._default_transport_timeout_s``
"""
return self._available
return transport_timeout_s if transport_timeout_s is not None else self._default_transport_timeout_s

# ======================================================================= #
# #
# Close & Connect #
# #
# ======================================================================= #
def close(self):
"""Close the connection via the provided transport's ``close()`` method.
Expand Down Expand Up @@ -212,7 +245,7 @@ def connect(self, rsa_keys=None, transport_timeout_s=None, auth_timeout_s=consta

# 2. Send a ``b'CNXN'`` message
msg = AdbMessage(constants.CNXN, constants.VERSION, constants.MAX_ADB_DATA, b'host::%s\0' % self._banner)
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
self._send(msg, adb_info)

# 3. Unpack the ``cmd``, ``arg0``, ``arg1``, and ``banner`` fields from the response
Expand Down Expand Up @@ -297,7 +330,7 @@ def _service(self, service, command, transport_timeout_s=None, read_timeout_s=co
The output of the ADB command as a string if ``decode`` is True, otherwise as bytes.
"""
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s, timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s, timeout_s)
if decode:
return b''.join(self._streaming_command(service, command, adb_info)).decode('utf8')
return b''.join(self._streaming_command(service, command, adb_info))
Expand Down Expand Up @@ -325,7 +358,7 @@ def _streaming_service(self, service, command, transport_timeout_s=None, read_ti
The line-by-line output of the ADB command as a string if ``decode`` is True, otherwise as bytes.
"""
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
stream = self._streaming_command(service, command, adb_info)
if decode:
for line in (stream_line.decode('utf8') for stream_line in stream):
Expand Down Expand Up @@ -438,7 +471,7 @@ def list(self, device_path, transport_timeout_s=None, read_timeout_s=constants.D
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_LIST_FORMAT, maxdata=self._maxdata)
self._open(b'sync:', adb_info)

Expand Down Expand Up @@ -478,7 +511,7 @@ def pull(self, device_path, local_path, progress_callback=None, transport_timeou
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_PULL_FORMAT, maxdata=self._maxdata)

with open(local_path, 'wb') as stream:
Expand Down Expand Up @@ -549,7 +582,7 @@ def push(self, local_path, device_path, st_mode=constants.DEFAULT_PUSH_MODE, mti
self.shell("mkdir " + device_path, transport_timeout_s, read_timeout_s)

for _local_path, _device_path in zip(local_paths, device_paths):
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_PUSH_FORMAT, maxdata=self._maxdata)

with open(_local_path, 'rb') as stream:
Expand Down Expand Up @@ -639,7 +672,7 @@ def stat(self, device_path, transport_timeout_s=None, read_timeout_s=constants.D
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
self._open(b'sync:', adb_info)

filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_STAT_FORMAT, maxdata=self._maxdata)
Expand Down Expand Up @@ -1161,14 +1194,18 @@ class AdbDeviceTcp(AdbDevice):
Whether an ADB connection to the device has been established
_banner : bytearray, bytes
The hostname of the machine where the Python interpreter is currently running
_default_transport_timeout_s : float, None
TODO
_maxdata : int
TODO
_transport : TcpTransport
The transport that is used to connect to the device
"""

def __init__(self, host, port=5555, default_transport_timeout_s=None, banner=None):
transport = TcpTransport(host, port, default_transport_timeout_s)
super(AdbDeviceTcp, self).__init__(transport, banner)
transport = TcpTransport(host, port)
super(AdbDeviceTcp, self).__init__(transport, default_transport_timeout_s, banner)


class AdbDeviceUsb(AdbDevice):
Expand Down Expand Up @@ -1197,6 +1234,10 @@ class AdbDeviceUsb(AdbDevice):
Whether an ADB connection to the device has been established
_banner : bytearray, bytes
The hostname of the machine where the Python interpreter is currently running
_default_transport_timeout_s : float, None
TODO
_maxdata : int
TODO
_transport : UsbTransport
The transport that is used to connect to the device
Expand All @@ -1207,4 +1248,4 @@ def __init__(self, serial=None, port_path=None, default_transport_timeout_s=None
raise exceptions.InvalidTransportError("To enable USB support you must install this package via `pip install adb-shell[usb]`")

transport = UsbTransport.find_adb(serial, port_path, default_transport_timeout_s)
super(AdbDeviceUsb, self).__init__(transport, banner)
super(AdbDeviceUsb, self).__init__(transport, default_transport_timeout_s, banner)
69 changes: 53 additions & 16 deletions adb_shell/adb_device_async.py
Expand Up @@ -84,9 +84,13 @@ class AdbDeviceAsync(object):
----------
transport : BaseTransportAsync
A user-provided transport for communicating with the device; must be an instance of a subclass of :class:`~adb_shell.transport.base_transport_async.BaseTransportAsync`
default_transport_timeout_s : float, None
TODO
banner : str, bytes, None
The hostname of the machine where the Python interpreter is currently running; if
it is not provided, it will be determined via ``socket.gethostname()``
default_transport_timeout_s : float, None
Default timeout in seconds for transport packets, or ``None``
Raises
------
Expand All @@ -99,14 +103,16 @@ class AdbDeviceAsync(object):
Whether an ADB connection to the device has been established
_banner : bytearray, bytes
The hostname of the machine where the Python interpreter is currently running
_default_transport_timeout_s : float, None
TODO
_maxdata: int
Maximum amount of data in an ADB packet
_transport : BaseTransportAsync
The transport that is used to connect to the device; must be a subclass of :class:`~adb_shell.transport.base_transport_async.BaseTransportAsync`
"""

def __init__(self, transport, banner=None):
def __init__(self, transport, default_transport_timeout_s=None, banner=None):
if banner and not isinstance(banner, (bytes, bytearray)):
self._banner = bytearray(banner, 'utf-8')
else:
Expand All @@ -118,8 +124,26 @@ def __init__(self, transport, banner=None):
self._transport = transport

self._available = False
self._default_transport_timeout_s = default_transport_timeout_s
self._maxdata = constants.MAX_PUSH_DATA

# ======================================================================= #
# #
# Properties & simple methods #
# #
# ======================================================================= #
@property
def available(self):
"""Whether or not an ADB connection to the device has been established.
Returns
-------
bool
``self._available``
"""
return self._available

@property
def max_chunk_size(self):
"""Maximum chunk size for filesync operations
Expand All @@ -132,18 +156,27 @@ def max_chunk_size(self):
"""
return min(constants.MAX_CHUNK_SIZE, self._maxdata // 2) or constants.MAX_PUSH_DATA

@property
def available(self):
"""Whether or not an ADB connection to the device has been established.
def _get_transport_timeout_s(self, transport_timeout_s):
"""Use the provided ``transport_timeout_s`` if it is not ``None``; otherwise, use ``self._default_transport_timeout_s``
Parameters
----------
transport_timeout_s : float, None
The potential transport timeout
Returns
-------
bool
``self._available``
float
``transport_timeout_s`` if it is not ``None``; otherwise, ``self._default_transport_timeout_s``
"""
return self._available
return transport_timeout_s if transport_timeout_s is not None else self._default_transport_timeout_s

# ======================================================================= #
# #
# Close & Connect #
# #
# ======================================================================= #
async def close(self):
"""Close the connection via the provided transport's ``close()`` method.
Expand Down Expand Up @@ -207,7 +240,7 @@ async def connect(self, rsa_keys=None, transport_timeout_s=None, auth_timeout_s=

# 2. Send a ``b'CNXN'`` message
msg = AdbMessage(constants.CNXN, constants.VERSION, constants.MAX_ADB_DATA, b'host::%s\0' % self._banner)
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
await self._send(msg, adb_info)

# 3. Unpack the ``cmd``, ``arg0``, ``arg1``, and ``banner`` fields from the response
Expand Down Expand Up @@ -292,7 +325,7 @@ async def _service(self, service, command, transport_timeout_s=None, read_timeou
The output of the ADB command as a string if ``decode`` is True, otherwise as bytes.
"""
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s, timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s, timeout_s)
if decode:
return b''.join([x async for x in self._streaming_command(service, command, adb_info)]).decode('utf8')
return b''.join([x async for x in self._streaming_command(service, command, adb_info)])
Expand Down Expand Up @@ -320,7 +353,7 @@ async def _streaming_service(self, service, command, transport_timeout_s=None, r
The line-by-line output of the ADB command as a string if ``decode`` is True, otherwise as bytes.
"""
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
stream = self._streaming_command(service, command, adb_info)
if decode:
async for line in (stream_line.decode('utf8') async for stream_line in stream):
Expand Down Expand Up @@ -433,7 +466,7 @@ async def list(self, device_path, transport_timeout_s=None, read_timeout_s=const
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDeviceAsync.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_LIST_FORMAT, maxdata=self._maxdata)
await self._open(b'sync:', adb_info)

Expand Down Expand Up @@ -473,7 +506,7 @@ async def pull(self, device_path, local_path, progress_callback=None, transport_
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDeviceAsync.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_PULL_FORMAT, maxdata=self._maxdata)

async with aiofiles.open(local_path, 'wb') as stream:
Expand Down Expand Up @@ -544,7 +577,7 @@ async def push(self, local_path, device_path, st_mode=constants.DEFAULT_PUSH_MOD
await self.shell("mkdir " + device_path, transport_timeout_s, read_timeout_s)

for _local_path, _device_path in zip(local_paths, device_paths):
adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_PUSH_FORMAT, maxdata=self._maxdata)

async with aiofiles.open(_local_path, 'rb') as stream:
Expand Down Expand Up @@ -634,7 +667,7 @@ async def stat(self, device_path, transport_timeout_s=None, read_timeout_s=const
if not self.available:
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDeviceAsync.connect()`?)")

adb_info = _AdbTransactionInfo(None, None, transport_timeout_s, read_timeout_s)
adb_info = _AdbTransactionInfo(None, None, self._get_transport_timeout_s(transport_timeout_s), read_timeout_s)
await self._open(b'sync:', adb_info)

filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_STAT_FORMAT, maxdata=self._maxdata)
Expand Down Expand Up @@ -1156,11 +1189,15 @@ class AdbDeviceTcpAsync(AdbDeviceAsync):
Whether an ADB connection to the device has been established
_banner : bytearray, bytes
The hostname of the machine where the Python interpreter is currently running
_default_transport_timeout_s : float, None
TODO
_maxdata : int
TODO
_transport : TcpTransportAsync
The transport that is used to connect to the device
"""

def __init__(self, host, port=5555, default_transport_timeout_s=None, banner=None):
transport = TcpTransportAsync(host, port, default_transport_timeout_s)
super(AdbDeviceTcpAsync, self).__init__(transport, banner)
transport = TcpTransportAsync(host, port)
super(AdbDeviceTcpAsync, self).__init__(transport, default_transport_timeout_s, banner)

0 comments on commit 21d4ebb

Please sign in to comment.