Home | History | Annotate | Download | only in platform
      1 # Copyright 2014 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 import logging
      5 import os
      6 import re
      7 import subprocess
      8 
      9 from telemetry.core import util
     10 from telemetry.internal.platform import cros_device
     11 from telemetry.internal.platform import device
     12 from telemetry.internal.platform.profiler import monsoon
     13 
     14 from devil.android import device_blacklist
     15 from devil.android import device_errors
     16 from devil.android import device_utils
     17 from devil.android.sdk import adb_wrapper
     18 
     19 
     20 class AndroidDevice(device.Device):
     21   """ Class represents information for connecting to an android device.
     22 
     23   Attributes:
     24     device_id: the device's serial string created by adb to uniquely
     25       identify an emulator/device instance. This string can be found by running
     26       'adb devices' command
     27     enable_performance_mode: when this is set to True, android platform will be
     28     set to high performance mode after browser is started.
     29   """
     30   def __init__(self, device_id, enable_performance_mode=True):
     31     super(AndroidDevice, self).__init__(
     32         name='Android device %s' % device_id, guid=device_id)
     33     self._device_id = device_id
     34     self._enable_performance_mode = enable_performance_mode
     35 
     36   @classmethod
     37   def GetAllConnectedDevices(cls, blacklist):
     38     device_serials = GetDeviceSerials(blacklist)
     39     return [cls(s) for s in device_serials]
     40 
     41   @property
     42   def device_id(self):
     43     return self._device_id
     44 
     45   @property
     46   def enable_performance_mode(self):
     47     return self._enable_performance_mode
     48 
     49 
     50 def _ListSerialsOfHealthyOnlineDevices(blacklist):
     51   return [d.adb.GetDeviceSerial()
     52           for d in device_utils.DeviceUtils.HealthyDevices(blacklist)
     53           if d.IsOnline()]
     54 
     55 
     56 def GetDeviceSerials(blacklist):
     57   """Return the list of device serials of healthy devices.
     58 
     59   If a preferred device has been set with ANDROID_SERIAL, it will be first in
     60   the returned list. The arguments specify what devices to include in the list.
     61   """
     62 
     63   device_serials = _ListSerialsOfHealthyOnlineDevices(blacklist)
     64 
     65   # The monsoon provides power for the device, so for devices with no
     66   # real battery, we need to turn them on after the monsoon enables voltage
     67   # output to the device.
     68   if not device_serials:
     69     try:
     70       m = monsoon.Monsoon(wait=False)
     71       m.SetUsbPassthrough(1)
     72       m.SetVoltage(3.8)
     73       m.SetMaxCurrent(8)
     74       logging.warn("""
     75 Monsoon power monitor detected, but no Android devices.
     76 
     77 The Monsoon's power output has been enabled. Please now ensure that:
     78 
     79   1. The Monsoon's front and back USB are connected to the host.
     80   2. The device is connected to the Monsoon's main and USB channels.
     81   3. The device is turned on.
     82 
     83 Waiting for device...
     84 """)
     85       util.WaitFor(_ListSerialsOfHealthyOnlineDevices(blacklist), 600)
     86       device_serials = _ListSerialsOfHealthyOnlineDevices(blacklist)
     87     except IOError:
     88       return []
     89 
     90   preferred_device = os.environ.get('ANDROID_SERIAL')
     91   if preferred_device in device_serials:
     92     logging.warn(
     93         'ANDROID_SERIAL is defined. Put %s in the first of the'
     94         'discovered devices list.' % preferred_device)
     95     device_serials.remove(preferred_device)
     96     device_serials.insert(0, preferred_device)
     97   return device_serials
     98 
     99 
    100 def GetDevice(finder_options):
    101   """Return a Platform instance for the device specified by |finder_options|."""
    102   if not CanDiscoverDevices():
    103     logging.info(
    104         'No adb command found. Will not try searching for Android browsers.')
    105     return None
    106 
    107   if finder_options.android_blacklist_file:
    108     blacklist = device_blacklist.Blacklist(
    109         finder_options.android_blacklist_file)
    110   else:
    111     blacklist = None
    112 
    113   if (finder_options.device
    114       and finder_options.device in GetDeviceSerials(blacklist)):
    115     return AndroidDevice(
    116         finder_options.device,
    117         enable_performance_mode=not finder_options.no_performance_mode)
    118 
    119   devices = AndroidDevice.GetAllConnectedDevices(blacklist)
    120   if len(devices) == 0:
    121     logging.warn('No android devices found.')
    122     return None
    123   if len(devices) > 1:
    124     logging.warn(
    125         'Multiple devices attached. Please specify one of the following:\n' +
    126         '\n'.join(['  --device=%s' % d.device_id for d in devices]))
    127     return None
    128   return devices[0]
    129 
    130 
    131 def _HasValidAdb():
    132   """Returns true if adb is present.
    133 
    134   Note that this currently will return True even if the adb that's present
    135   cannot run on this system.
    136   """
    137   if os.name != 'posix' or cros_device.IsRunningOnCrOS():
    138     return False
    139 
    140   try:
    141     adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
    142   except device_errors.NoAdbError:
    143     return False
    144 
    145   if os.path.isabs(adb_path) and not os.path.exists(adb_path):
    146     return False
    147 
    148   return True
    149 
    150 
    151 def CanDiscoverDevices():
    152   """Returns true if devices are discoverable via adb."""
    153   if not _HasValidAdb():
    154     return False
    155 
    156   try:
    157     with open(os.devnull, 'w') as devnull:
    158       adb_process = subprocess.Popen(
    159           ['adb', 'devices'], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    160           stdin=devnull)
    161       stdout = adb_process.communicate()[0]
    162     if re.search(re.escape('????????????\tno permissions'), stdout) != None:
    163       logging.warn('adb devices gave a permissions error. '
    164                    'Consider running adb as root:')
    165       logging.warn('  adb kill-server')
    166       logging.warn('  sudo `which adb` devices\n\n')
    167     return True
    168   except OSError:
    169     pass
    170   try:
    171     adb_path = adb_wrapper.AdbWrapper.GetAdbPath()
    172     os.environ['PATH'] = os.pathsep.join(
    173         [os.path.dirname(adb_path), os.environ['PATH']])
    174     device_utils.DeviceUtils.HealthyDevices(None)
    175     return True
    176   except (device_errors.CommandFailedError, device_errors.CommandTimeoutError,
    177           device_errors.NoAdbError, OSError):
    178     return False
    179 
    180 
    181 def FindAllAvailableDevices(options):
    182   """Returns a list of available devices.
    183   """
    184   devices = []
    185   try:
    186     if CanDiscoverDevices():
    187       blacklist = None
    188       if options.android_blacklist_file:
    189         blacklist = device_blacklist.Blacklist(options.android_blacklist_file)
    190       devices = AndroidDevice.GetAllConnectedDevices(blacklist)
    191   finally:
    192     if not devices and _HasValidAdb():
    193       try:
    194         adb_wrapper.AdbWrapper.KillServer()
    195       except device_errors.NoAdbError as e:
    196         logging.warning(
    197             'adb reported as present, but NoAdbError thrown: %s', str(e))
    198 
    199   return devices
    200