[Android] Convert to DeviceUtils versions of IsOnline, HasRoot, and EnableRoot.

BUG=267773

Review URL: https://codereview.chromium.org/285143002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271213 0039d316-1c4b-4281-b951-d872f2087c98
parent 2b8710cc
...@@ -30,6 +30,7 @@ from pylib import android_commands ...@@ -30,6 +30,7 @@ from pylib import android_commands
from pylib import constants from pylib import constants
from pylib.cmd_helper import GetCmdOutput from pylib.cmd_helper import GetCmdOutput
from pylib.device import device_blacklist from pylib.device import device_blacklist
from pylib.device import device_errors
from pylib.device import device_utils from pylib.device import device_utils
def DeviceInfo(serial, options): def DeviceInfo(serial, options):
...@@ -95,7 +96,13 @@ def DeviceInfo(serial, options): ...@@ -95,7 +96,13 @@ def DeviceInfo(serial, options):
# Turn off devices with low battery. # Turn off devices with low battery.
if battery_level < 15: if battery_level < 15:
device_adb.old_interface.EnableAdbRoot() try:
device_adb.EnableRoot()
except device_errors.CommandFailedError as e:
# Attempt shutdown anyway.
# TODO(jbudorick) Handle this exception appropriately after interface
# conversions are finished.
logging.error(str(e))
device_adb.old_interface.Shutdown() device_adb.old_interface.Shutdown()
full_report = '\n'.join(report) full_report = '\n'.join(report)
return device_type, device_build, battery_level, full_report, errors, True return device_type, device_build, battery_level, full_report, errors, True
......
...@@ -17,6 +17,7 @@ BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..') ...@@ -17,6 +17,7 @@ BUILD_ANDROID_DIR = os.path.join(os.path.dirname(__file__), '..', '..')
sys.path.append(BUILD_ANDROID_DIR) sys.path.append(BUILD_ANDROID_DIR)
from pylib import android_commands from pylib import android_commands
from pylib.device import device_errors
from pylib.device import device_utils from pylib.device import device_utils
GetAttachedDevices = android_commands.GetAttachedDevices GetAttachedDevices = android_commands.GetAttachedDevices
...@@ -57,15 +58,20 @@ def GetConfigurationForDevice(device_id): ...@@ -57,15 +58,20 @@ def GetConfigurationForDevice(device_id):
device = device_utils.DeviceUtils(device_id) device = device_utils.DeviceUtils(device_id)
configuration = None configuration = None
has_root = False has_root = False
is_online = device.old_interface.IsOnline() is_online = device.IsOnline()
if is_online: if is_online:
cmd = 'ls -l /data/app; getprop ro.build.description' cmd = 'ls -l /data/app; getprop ro.build.description'
cmd_output = device.old_interface.RunShellCommand(cmd) cmd_output = device.old_interface.RunShellCommand(cmd)
has_root = not 'Permission denied' in cmd_output[0] has_root = not 'Permission denied' in cmd_output[0]
if not has_root: if not has_root:
# Disable warning log messages from EnableAdbRoot() # Disable warning log messages from EnableRoot()
logging.getLogger().disabled = True logging.getLogger().disabled = True
has_root = device.old_interface.EnableAdbRoot() try:
device.EnableRoot()
has_root = True
except device_errors.CommandFailedError:
has_root = False
finally:
logging.getLogger().disabled = False logging.getLogger().disabled = False
cmd_output = device.old_interface.RunShellCommand(cmd) cmd_output = device.old_interface.RunShellCommand(cmd)
......
...@@ -7,11 +7,20 @@ Function/method decorators that provide timeout and retry logic. ...@@ -7,11 +7,20 @@ Function/method decorators that provide timeout and retry logic.
""" """
import functools import functools
import os
import sys
from pylib import constants
from pylib.device import device_errors from pylib.device import device_errors
from pylib.utils import reraiser_thread from pylib.utils import reraiser_thread
from pylib.utils import timeout_retry from pylib.utils import timeout_retry
# TODO(jbudorick) Remove once the DeviceUtils implementations are no longer
# backed by AndroidCommands / android_testrunner.
sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 'third_party',
'android_testrunner'))
import errors as old_errors
def _TimeoutRetryWrapper(f, timeout_func, retries_func): def _TimeoutRetryWrapper(f, timeout_func, retries_func):
@functools.wraps(f) @functools.wraps(f)
...@@ -22,6 +31,10 @@ def _TimeoutRetryWrapper(f, timeout_func, retries_func): ...@@ -22,6 +31,10 @@ def _TimeoutRetryWrapper(f, timeout_func, retries_func):
return f(*args, **kwargs) return f(*args, **kwargs)
try: try:
return timeout_retry.Run(impl, timeout, retries) return timeout_retry.Run(impl, timeout, retries)
except old_errors.WaitForResponseTimedOutError as e:
raise device_errors.CommandTimeoutError(str(e))
except old_errors.DeviceUnresponsiveError as e:
raise device_errors.DeviceUnreachableError(str(e))
except reraiser_thread.TimeoutError as e: except reraiser_thread.TimeoutError as e:
raise device_errors.CommandTimeoutError(str(e)) raise device_errors.CommandTimeoutError(str(e))
return TimeoutRetryWrapper return TimeoutRetryWrapper
......
...@@ -16,6 +16,7 @@ import sys ...@@ -16,6 +16,7 @@ import sys
import pylib.android_commands import pylib.android_commands
from pylib.device import adb_wrapper from pylib.device import adb_wrapper
from pylib.device import decorators from pylib.device import decorators
from pylib.device import device_errors
CHROME_SRC_DIR = os.path.abspath( CHROME_SRC_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) os.path.join(os.path.dirname(__file__), '..', '..', '..', '..'))
...@@ -78,7 +79,20 @@ def RestartServer(): ...@@ -78,7 +79,20 @@ def RestartServer():
class DeviceUtils(object): class DeviceUtils(object):
def __init__(self, device): def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
default_retries=_DEFAULT_RETRIES):
""" DeviceUtils constructor.
Args:
device: Either a device serial, an existing AdbWrapper instance, an
an existing AndroidCommands instance, or nothing.
default_timeout: An integer containing the default number of seconds to
wait for an operation to complete if no explicit value
is provided.
default_retries: An integer containing the default number or times an
operation should be retried on failure if no explicit
value is provided.
"""
self.old_interface = None self.old_interface = None
if isinstance(device, basestring): if isinstance(device, basestring):
self.old_interface = pylib.android_commands.AndroidCommands(device) self.old_interface = pylib.android_commands.AndroidCommands(device)
...@@ -88,4 +102,51 @@ class DeviceUtils(object): ...@@ -88,4 +102,51 @@ class DeviceUtils(object):
self.old_interface = device self.old_interface = device
elif not device: elif not device:
self.old_interface = pylib.android_commands.AndroidCommands() self.old_interface = pylib.android_commands.AndroidCommands()
else:
raise ValueError('Unsupported type passed for argument "device"')
self._default_timeout = default_timeout
self._default_retries = default_retries
@decorators.WithTimeoutAndRetriesFromInstance(
'_default_timeout', '_default_retries')
def IsOnline(self, timeout=None, retries=None):
""" Checks whether the device is online.
Args:
timeout: An integer containing the number of seconds to wait for the
operation to complete.
retries: An integer containing the number of times the operation should
be retried if it fails.
Returns:
True if the device is online, False otherwise.
"""
return self.old_interface.IsOnline()
@decorators.WithTimeoutAndRetriesFromInstance(
'_default_timeout', '_default_retries')
def HasRoot(self, timeout=None, retries=None):
""" Checks whether or not adbd has root privileges.
Args:
timeout: Same as for |IsOnline|.
retries: Same as for |IsOnline|.
Returns:
True if adbd has root privileges, False otherwise.
"""
return self.old_interface.IsRootEnabled()
@decorators.WithTimeoutAndRetriesFromInstance(
'_default_timeout', '_default_retries')
def EnableRoot(self, timeout=None, retries=None):
""" Restarts adbd with root privileges.
Args:
timeout: Same as for |IsOnline|.
retries: Same as for |IsOnline|.
Raises:
CommandFailedError if root could not be enabled.
"""
if not self.old_interface.EnableAdbRoot():
raise device_errors.CommandFailedError(
'adb root', 'Could not enable root.')
...@@ -9,10 +9,13 @@ Unit tests for the contents of device_utils.py (mostly DeviceUtils). ...@@ -9,10 +9,13 @@ Unit tests for the contents of device_utils.py (mostly DeviceUtils).
# pylint: disable=W0212 # pylint: disable=W0212
# pylint: disable=W0613 # pylint: disable=W0613
import random
import unittest import unittest
from pylib import android_commands from pylib import android_commands
from pylib import cmd_helper from pylib import cmd_helper
from pylib.device import adb_wrapper from pylib.device import adb_wrapper
from pylib.device import device_errors
from pylib.device import device_utils from pylib.device import device_utils
...@@ -21,9 +24,10 @@ class DeviceUtilsTest(unittest.TestCase): ...@@ -21,9 +24,10 @@ class DeviceUtilsTest(unittest.TestCase):
pass pass
def testRestartServerNotRunning(self): def testRestartServerNotRunning(self):
# TODO(jbudorick) If these fail, it's not DeviceUtils's fault. self.assertEqual(0, cmd_helper.RunCmd(['pkill', 'adb']),
self.assertEqual(0, cmd_helper.RunCmd(['pkill', 'adb'])) msg='Unable to kill adb during setup.')
self.assertNotEqual(0, cmd_helper.RunCmd(['pgrep', 'adb'])) self.assertNotEqual(0, cmd_helper.RunCmd(['pgrep', 'adb']),
msg='Unexpectedly found adb during setup.')
device_utils.RestartServer() device_utils.RestartServer()
self.assertEqual(0, cmd_helper.RunCmd(['pgrep', 'adb'])) self.assertEqual(0, cmd_helper.RunCmd(['pgrep', 'adb']))
...@@ -63,7 +67,83 @@ class DeviceUtilsTest(unittest.TestCase): ...@@ -63,7 +67,83 @@ class DeviceUtilsTest(unittest.TestCase):
d = device_utils.DeviceUtils(None) d = device_utils.DeviceUtils(None)
self.assertIsNone(d.old_interface.GetDevice()) self.assertIsNone(d.old_interface.GetDevice())
@staticmethod
def _getTestAdbWrapper():
devices = adb_wrapper.AdbWrapper.GetDevices()
if devices:
return random.choice(devices)
return None
@staticmethod
def _getUnusedSerial():
used_devices = [str(d) for d in adb_wrapper.AdbWrapper.GetDevices()]
while True:
serial = ''
for _ in xrange(0, 16):
serial += random.choice('0123456789abcdef')
if serial not in used_devices:
return serial
def testIsOnline(self):
d = device_utils.DeviceUtils(self._getTestAdbWrapper())
self.assertTrue(d is None or d.IsOnline())
d = device_utils.DeviceUtils(self._getUnusedSerial())
self.assertFalse(d.IsOnline())
def testHasRoot(self):
a = self._getTestAdbWrapper()
d = device_utils.DeviceUtils(a)
secure_prop = a.Shell('getprop ro.secure').strip()
if secure_prop == '1':
build_type_prop = a.Shell('getprop ro.build.type').strip()
if build_type_prop == 'userdebug':
adb_root_prop = a.Shell('getprop service.adb.root').strip()
if adb_root_prop is None or adb_root_prop == '0':
self.assertFalse(d.HasRoot())
else:
self.assertTrue(d.HasRoot())
else:
self.assertFalse(d.HasRoot())
else:
self.assertTrue(d.HasRoot())
def testEnableRoot(self):
a = self._getTestAdbWrapper()
d = device_utils.DeviceUtils(a)
secure_prop = a.Shell('getprop ro.secure').strip()
if secure_prop == '1':
build_type_prop = a.Shell('getprop ro.build.type').strip()
if build_type_prop == 'userdebug':
# Turn off the adb root property
adb_root_prop = a.Shell('getprop service.adb.root').strip()
if adb_root_prop == '1':
a.Shell('setprop service.adb.root 0')
# Make sure that adbd is running without root by restarting it
ps_out = a.Shell('ps')
adbd_pids = []
for line in ps_out.splitlines():
if 'adbd' in line:
pid = line.split()[1]
adbd_pids.append(pid)
for pid in adbd_pids:
a.Shell('kill %s' % str(pid))
a.WaitForDevice()
self.assertFalse(d.HasRoot())
d.EnableRoot()
self.assertTrue(d.HasRoot())
else:
self.assertFalse(d.HasRoot())
with self.assertRaises(device_errors.CommandFailedError):
d.EnableRoot()
else:
self.assertTrue(d.HasRoot())
d.EnableRoot()
self.assertTrue(d.HasRoot())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main(verbosity=2, buffer=True)
...@@ -128,7 +128,7 @@ class TestRunner(base_test_runner.BaseTestRunner): ...@@ -128,7 +128,7 @@ class TestRunner(base_test_runner.BaseTestRunner):
logging.error('Test terminated - EOF') logging.error('Test terminated - EOF')
# We're here because either the device went offline, or the test harness # We're here because either the device went offline, or the test harness
# crashed without outputting the CRASHED marker (crbug.com/175538). # crashed without outputting the CRASHED marker (crbug.com/175538).
if not self.device.old_interface.IsOnline(): if not self.device.IsOnline():
raise device_errors.DeviceUnreachableError( raise device_errors.DeviceUnreachableError(
'Device %s went offline.' % self.device.old_interface.GetDevice()) 'Device %s went offline.' % self.device.old_interface.GetDevice())
if full_test_name: if full_test_name:
......
...@@ -147,7 +147,7 @@ class TestRunner(base_test_runner.BaseTestRunner): ...@@ -147,7 +147,7 @@ class TestRunner(base_test_runner.BaseTestRunner):
def SetUp(self): def SetUp(self):
"""Sets up the test harness and device before all tests are run.""" """Sets up the test harness and device before all tests are run."""
super(TestRunner, self).SetUp() super(TestRunner, self).SetUp()
if not self.device.old_interface.IsRootEnabled(): if not self.device.HasRoot():
logging.warning('Unable to enable java asserts for %s, non rooted device', logging.warning('Unable to enable java asserts for %s, non rooted device',
str(self.device)) str(self.device))
else: else:
......
...@@ -7,8 +7,10 @@ import psutil ...@@ -7,8 +7,10 @@ import psutil
import signal import signal
from pylib import android_commands from pylib import android_commands
from pylib.device import device_errors
from pylib.device import device_utils from pylib.device import device_utils
def _KillWebServers(): def _KillWebServers():
for s in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT, signal.SIGKILL]: for s in [signal.SIGTERM, signal.SIGINT, signal.SIGQUIT, signal.SIGKILL]:
signalled = [] signalled = []
...@@ -41,6 +43,11 @@ def CleanupLeftoverProcesses(): ...@@ -41,6 +43,11 @@ def CleanupLeftoverProcesses():
device_utils.RestartServer() device_utils.RestartServer()
did_restart_host_adb = True did_restart_host_adb = True
device.old_interface.RestartAdbdOnDevice() device.old_interface.RestartAdbdOnDevice()
device.old_interface.EnableAdbRoot() try:
device.EnableRoot()
except device_errors.CommandFailedError as e:
# TODO(jbudorick) Handle this exception appropriately after interface
# conversions are finished.
logging.error(str(e))
device.old_interface.WaitForDevicePm() device.old_interface.WaitForDevicePm()
...@@ -23,11 +23,13 @@ Call tool.CleanUpEnvironment(). ...@@ -23,11 +23,13 @@ Call tool.CleanUpEnvironment().
# pylint: disable=R0201 # pylint: disable=R0201
import glob import glob
import logging
import os.path import os.path
import subprocess import subprocess
import sys import sys
from pylib.constants import DIR_SOURCE_ROOT from pylib.constants import DIR_SOURCE_ROOT
from pylib.device import device_errors
def SetChromeTimeoutScale(device, scale): def SetChromeTimeoutScale(device, scale):
...@@ -132,7 +134,13 @@ class AddressSanitizerTool(BaseTool): ...@@ -132,7 +134,13 @@ class AddressSanitizerTool(BaseTool):
return self.GetTestWrapper() return self.GetTestWrapper()
def SetupEnvironment(self): def SetupEnvironment(self):
self._device.old_interface.EnableAdbRoot() try:
self._device.EnableRoot()
except device_errors.CommandFailedError as e:
# Try to set the timeout scale anyway.
# TODO(jbudorick) Handle this exception appropriately after interface
# conversions are finished.
logging.error(str(e))
SetChromeTimeoutScale(self._device, self.GetTimeoutScale()) SetChromeTimeoutScale(self._device, self.GetTimeoutScale())
def CleanUpEnvironment(self): def CleanUpEnvironment(self):
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# found in the LICENSE file. # found in the LICENSE file.
import collections import collections
import logging
import optparse import optparse
import os import os
import sys import sys
...@@ -86,7 +87,13 @@ def main(argv): ...@@ -86,7 +87,13 @@ def main(argv):
device = device_utils.DeviceUtils(None) device = device_utils.DeviceUtils(None)
device.old_interface.EnableAdbRoot() try:
device.EnableRoot()
except device_errors.CommandFailedError as e:
# Try to change the flags and start the activity anyway.
# TODO(jbudorick) Handle this exception appropriately after interface
# conversions are finished.
logging.error(str(e))
flags = flag_changer.FlagChanger(device, package_info.cmdline_file) flags = flag_changer.FlagChanger(device, package_info.cmdline_file)
if ENABLE_TEST_INTENTS_FLAG not in flags.Get(): if ENABLE_TEST_INTENTS_FLAG not in flags.Get():
flags.AddFlags([ENABLE_TEST_INTENTS_FLAG]) flags.AddFlags([ENABLE_TEST_INTENTS_FLAG])
......
...@@ -11,6 +11,7 @@ import datetime ...@@ -11,6 +11,7 @@ import datetime
import glob import glob
import hashlib import hashlib
import json import json
import logging
import os import os
import posixpath import posixpath
...@@ -26,6 +27,7 @@ from memory_inspector.core import symbol ...@@ -26,6 +27,7 @@ from memory_inspector.core import symbol
# The memory_inspector/__init__ module will add the <CHROME_SRC>/build/android # The memory_inspector/__init__ module will add the <CHROME_SRC>/build/android
# deps to the PYTHONPATH for pylib. # deps to the PYTHONPATH for pylib.
from pylib import android_commands from pylib import android_commands
from pylib.device import device_errors
from pylib.device import device_utils from pylib.device import device_utils
from pylib.symbols import elf_symbolizer from pylib.symbols import elf_symbolizer
...@@ -173,7 +175,13 @@ class AndroidDevice(backends.Device): ...@@ -173,7 +175,13 @@ class AndroidDevice(backends.Device):
def Initialize(self): def Initialize(self):
"""Starts adb root and deploys the prebuilt binaries on initialization.""" """Starts adb root and deploys the prebuilt binaries on initialization."""
self.underlying_device.old_interface.EnableAdbRoot() try:
self.underlying_device.EnableRoot()
except device_errors.CommandFailedError as e:
# Try to deploy memdump and ps_ext anyway.
# TODO(jbudorick) Handle this exception appropriately after interface
# conversions are finished.
logging.error(str(e))
# Download (from GCS) and deploy prebuilt helper binaries on the device. # Download (from GCS) and deploy prebuilt helper binaries on the device.
self._DeployPrebuiltOnDeviceIfNeeded(_MEMDUMP_PREBUILT_PATH, self._DeployPrebuiltOnDeviceIfNeeded(_MEMDUMP_PREBUILT_PATH,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment