adb.py supports Android N+ versions of adb as well.
Bug: 38512781
Fix: 38512781
Test: acts_adb_test.py
Test: act.py -c <> -tc BleScanApiTest
Change-Id: If8afc826c167239579cc0a22852d444b8392f181
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3e39a38..ca749eb 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,5 +1,6 @@
[Hook Scripts]
acts_base_class_test = ./acts/framework/tests/acts_base_class_test.py
+acts_adb_test = ./acts/framework/tests/acts_adb_test.py
acts_android_device_test = ./acts/framework/tests/acts_android_device_test.py
acts_asserts_test = ./acts/framework/tests/acts_asserts_test.py
acts_base_class_test = ./acts/framework/tests/acts_base_class_test.py
diff --git a/acts/framework/acts/controllers/adb.py b/acts/framework/acts/controllers/adb.py
index 2a1b69d..68c96de 100644
--- a/acts/framework/acts/controllers/adb.py
+++ b/acts/framework/acts/controllers/adb.py
@@ -29,6 +29,9 @@
DEFAULT_ADB_TIMEOUT = 60
DEFAULT_ADB_PULL_TIMEOUT = 180
+# Uses a regex to be backwards compatible with previous versions of ADB
+# (N and above add the serial to the error msg).
+DEVICE_NOT_FOUND_REGEX = re.compile('^error: device (?:\'.*?\' )?not found')
def parsing_parcel_output(output):
@@ -107,31 +110,28 @@
def _exec_cmd(self, cmd, ignore_status=False, timeout=DEFAULT_ADB_TIMEOUT):
"""Executes adb commands in a new shell.
- This is specific to executing adb binary because stderr is not a good
- indicator of cmd execution status.
+ This is specific to executing adb commands.
Args:
- cmds: A string that is the adb command to execute.
+ cmd: A string that is the adb command to execute.
Returns:
- The output of the adb command run if exit code is 0.
+ The stdout of the adb command.
Raises:
- AdbError is raised if the adb command exit code is not 0.
+ AdbError is raised if adb cannot find the device.
"""
result = job.run(cmd, ignore_status=True, timeout=timeout)
ret, out, err = result.exit_status, result.stdout, result.stderr
logging.debug("cmd: %s, stdout: %s, stderr: %s, ret: %s", cmd, out,
err, ret)
-
- if ret == 0 or ignore_status:
- if "Result: Parcel" in out:
- return parsing_parcel_output(out)
- else:
- return out
- else:
+ if not ignore_status and ret == 1 and DEVICE_NOT_FOUND_REGEX.match(err):
raise AdbError(cmd=cmd, stdout=out, stderr=err, ret_code=ret)
+ elif "Result: Parcel" in out:
+ return parsing_parcel_output(out)
+ else:
+ return out
def _exec_adb_cmd(self, name, arg_str, **kwargs):
return self._exec_cmd(' '.join((self.adb_str, name, arg_str)),
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index b5f00da..72c1b76 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -776,17 +776,12 @@
True if package is installed. False otherwise.
"""
try:
- out = self.adb.shell(
- 'pm list packages | grep -w "package:%s"' % package_name,
- ignore_status=False)
- if package_name in out:
- self.log.debug("apk %s is installed", package_name)
- return True
- else:
- self.log.debug("apk %s is not installed, query returns %s",
- package_name, out)
- return False
- except:
+ return not self.adb.shell(
+ 'pm list packages | grep -w "package:%s"' % package_name)
+
+ except Exception as err:
+ self.log.error('Could not determine if %s is installed. '
+ 'Received error:\n%s', package_name, err)
return False
def is_sl4a_installed(self):
diff --git a/acts/framework/tests/acts_adb_test.py b/acts/framework/tests/acts_adb_test.py
new file mode 100755
index 0000000..be2535a
--- /dev/null
+++ b/acts/framework/tests/acts_adb_test.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# Copyright 2017 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import mock
+from acts.controllers.adb import AdbProxy
+from acts.controllers.adb import AdbError
+
+
+class MockJob(object):
+ def __init__(self, exit_status=0, stderr='', stdout=''):
+ self.exit_status = exit_status
+ self.stderr = stderr
+ self.stdout = stdout
+
+
+class MockAdbProxy(AdbProxy):
+ def __init__(self):
+ pass
+
+
+class ADBTest(unittest.TestCase):
+ """A class for testing acts/controllers/adb.py"""
+
+ def test__exec_cmd_failure_old_adb(self):
+ mock_job = MockJob(exit_status=1, stderr='error: device not found')
+ cmd = ['adb', '-s', '"SOME_SERIAL"', 'shell', '"SOME_SHELL_CMD"']
+ with mock.patch('acts.libs.proc.job.run', return_value=mock_job):
+ with self.assertRaises(AdbError):
+ MockAdbProxy()._exec_cmd(cmd)
+
+ def test__exec_cmd_failure_new_adb(self):
+ mock_job = MockJob(
+ exit_status=1, stderr='error: device \'DEADBEEF\' not found')
+ cmd = ['adb', '-s', '"SOME_SERIAL"', 'shell', '"SOME_SHELL_CMD"']
+ with mock.patch('acts.libs.proc.job.run', return_value=mock_job):
+ with self.assertRaises(AdbError):
+ MockAdbProxy()._exec_cmd(cmd)
+
+ def test__exec_cmd_pass_ret_1(self):
+ mock_job = MockJob(exit_status=1, stderr='error not related to adb')
+ cmd = ['adb', '-s', '"SOME_SERIAL"', 'shell', '"SOME_SHELL_CMD"']
+ with mock.patch('acts.libs.proc.job.run', return_value=mock_job):
+ MockAdbProxy()._exec_cmd(cmd)
+
+ def test__exec_cmd_pass_basic(self):
+ mock_job = MockJob(exit_status=0, stderr='', stdout='FEEDACAB')
+ cmd = ['adb', '-s', '"SOME_SERIAL"', 'shell', '"SOME_SHELL_CMD"']
+ with mock.patch('acts.libs.proc.job.run', return_value=mock_job):
+ MockAdbProxy()._exec_cmd(cmd)
+
+ def test__exec_cmd_pass_no_stdout(self):
+ mock_job = MockJob(exit_status=0, stderr='', stdout='')
+ cmd = ['adb', '-s', '"SOME_SERIAL"', 'shell', '"SOME_SHELL_CMD"']
+ with mock.patch('acts.libs.proc.job.run', return_value=mock_job):
+ MockAdbProxy()._exec_cmd(cmd)
+
+
+if __name__ == "__main__":
+ unittest.main()