Skip to content

Commit f5c6229

Browse files
authored
Check the connection to the device before sending ADB commands (#89)
* Check the connection to the device before sending ADB commands * Linting fix
1 parent 865d721 commit f5c6229

3 files changed

Lines changed: 49 additions & 4 deletions

File tree

adb_shell/adb_device.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,9 @@ def shell(self, command, timeout_s=None, total_timeout_s=constants.DEFAULT_TOTAL
457457
The output of the ADB shell command as a string if ``decode`` is True, otherwise as bytes.
458458
459459
"""
460+
if not self.available:
461+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
462+
460463
return self._service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode)
461464

462465
def streaming_shell(self, command, timeout_s=None, total_timeout_s=constants.DEFAULT_TOTAL_TIMEOUT_S, decode=True):
@@ -480,6 +483,9 @@ def streaming_shell(self, command, timeout_s=None, total_timeout_s=constants.DEF
480483
The line-by-line output of the ADB shell command as a string if ``decode`` is True, otherwise as bytes.
481484
482485
"""
486+
if not self.available:
487+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
488+
483489
for line in self._streaming_service(b'shell', command.encode('utf8'), timeout_s, total_timeout_s, decode):
484490
yield line
485491

@@ -506,6 +512,9 @@ def list(self, device_path, timeout_s=None, total_timeout_s=constants.DEFAULT_TO
506512
Filename, mode, size, and mtime info for the files in the directory
507513
508514
"""
515+
if not self.available:
516+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
517+
509518
adb_info = _AdbTransactionInfo(None, None, timeout_s, total_timeout_s)
510519
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_LIST_FORMAT)
511520
self._open(b'sync:', adb_info)
@@ -552,6 +561,9 @@ def pull(self, device_filename, dest_file=None, progress_callback=None, timeout_
552561
If ``dest_file`` is of unknown type.
553562
554563
"""
564+
if not self.available:
565+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
566+
555567
if not dest_file:
556568
dest_file = io.BytesIO()
557569

@@ -628,6 +640,9 @@ def push(self, source_file, device_filename, st_mode=constants.DEFAULT_PUSH_MODE
628640
The total time in seconds to wait for a ``b'CLSE'`` or ``b'OKAY'`` command in :meth:`AdbDevice._read`
629641
630642
"""
643+
if not self.available:
644+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
645+
631646
if isinstance(source_file, str):
632647
if os.path.isdir(source_file):
633648
self.shell("mkdir " + device_filename, timeout_s, total_timeout_s)
@@ -720,12 +735,15 @@ def stat(self, device_filename, timeout_s=None, total_timeout_s=constants.DEFAUL
720735
The last modified time for the file
721736
722737
"""
738+
if not self.available:
739+
raise exceptions.AdbConnectionError("ADB command not sent because a connection to the device has not been established. (Did you call `AdbDevice.connect()`?)")
740+
723741
adb_info = _AdbTransactionInfo(None, None, timeout_s, total_timeout_s)
724742
self._open(b'sync:', adb_info)
725743

726744
filesync_info = _FileSyncTransactionInfo(constants.FILESYNC_STAT_FORMAT)
727745
self._filesync_send(constants.STAT, adb_info, filesync_info, data=device_filename)
728-
_, (mode, size, mtime) = self._filesync_read([constants.STAT], adb_info, filesync_info, read_data=False)
746+
_, (mode, size, mtime), _ = self._filesync_read([constants.STAT], adb_info, filesync_info, read_data=False)
729747
self._close(adb_info)
730748

731749
return mode, size, mtime
@@ -1069,8 +1087,8 @@ def _filesync_read(self, expected_ids, adb_info, filesync_info, read_data=True):
10691087
The received header ID
10701088
tuple
10711089
The contents of the header
1072-
data : bytearray
1073-
The received data
1090+
data : bytearray, None
1091+
The received data, or ``None`` if ``read_data`` is False
10741092
10751093
Raises
10761094
------
@@ -1100,7 +1118,7 @@ def _filesync_read(self, expected_ids, adb_info, filesync_info, read_data=True):
11001118
raise exceptions.InvalidResponseError('Expected one of %s, got %s' % (expected_ids, command_id))
11011119

11021120
if not read_data:
1103-
return command_id, header[1:]
1121+
return command_id, header[1:], None
11041122

11051123
# Header is (ID, ..., size).
11061124
size = header[-1]

adb_shell/exceptions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ class AdbCommandFailureException(Exception):
3232
"""
3333

3434

35+
class AdbConnectionError(Exception):
36+
"""ADB command not sent because a connection to the device has not been established.
37+
38+
"""
39+
40+
3541
class DeviceAuthError(Exception):
3642
"""Device authentication failed.
3743

tests/test_adb_device.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,27 @@ def setUp(self):
4646
def tearDown(self):
4747
self.assertFalse(self.device._handle._bulk_read)
4848

49+
def test_adb_connection_error(self):
50+
with self.assertRaises(exceptions.AdbConnectionError):
51+
self.device.shell('FAIL')
52+
53+
with self.assertRaises(exceptions.AdbConnectionError):
54+
''.join(self.device.streaming_shell('FAIL'))
55+
56+
with self.assertRaises(exceptions.AdbConnectionError):
57+
self.device.list('FAIL')
58+
59+
with self.assertRaises(exceptions.AdbConnectionError):
60+
self.device.push('FAIL', 'FAIL')
61+
62+
with self.assertRaises(exceptions.AdbConnectionError):
63+
self.device.pull('FAIL', 'FAIL')
64+
65+
with self.assertRaises(exceptions.AdbConnectionError):
66+
self.device.stat('FAIL')
67+
68+
self.device._handle._bulk_read = b''
69+
4970
def test_init_tcp(self):
5071
with patchers.PATCH_TCP_HANDLE:
5172
tcp_device = AdbDeviceTcp('host')

0 commit comments

Comments
 (0)