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
5import logging
6import os
7
8from telemetry.core import util
9from telemetry.internal.platform import cros_device
10from telemetry.internal.platform import device
11from telemetry.internal.platform.profiler import monsoon
12
13from devil.android import device_blacklist
14from devil.android import device_errors
15from devil.android import device_utils
16from devil.android.sdk import adb_wrapper
17
18
19class AndroidDevice(device.Device):
20  """ Class represents information for connecting to an android device.
21
22  Attributes:
23    device_id: the device's serial string created by adb to uniquely
24      identify an emulator/device instance. This string can be found by running
25      'adb devices' command
26    enable_performance_mode: when this is set to True, android platform will be
27    set to high performance mode after browser is started.
28  """
29  def __init__(self, device_id, enable_performance_mode=True):
30    super(AndroidDevice, self).__init__(
31        name='Android device %s' % device_id, guid=device_id)
32    self._device_id = device_id
33    self._enable_performance_mode = enable_performance_mode
34
35  @classmethod
36  def GetAllConnectedDevices(cls, blacklist):
37    device_serials = GetDeviceSerials(blacklist)
38    return [cls(s) for s in device_serials]
39
40  @property
41  def device_id(self):
42    return self._device_id
43
44  @property
45  def enable_performance_mode(self):
46    return self._enable_performance_mode
47
48
49def _ListSerialsOfHealthyOnlineDevices(blacklist):
50  return [d.adb.GetDeviceSerial()
51          for d in device_utils.DeviceUtils.HealthyDevices(blacklist)
52          if d.IsOnline()]
53
54
55def GetDeviceSerials(blacklist):
56  """Return the list of device serials of healthy devices.
57
58  If a preferred device has been set with ANDROID_SERIAL, it will be first in
59  the returned list. The arguments specify what devices to include in the list.
60  """
61
62  device_serials = _ListSerialsOfHealthyOnlineDevices(blacklist)
63
64  # The monsoon provides power for the device, so for devices with no
65  # real battery, we need to turn them on after the monsoon enables voltage
66  # output to the device.
67  if not device_serials:
68    try:
69      m = monsoon.Monsoon(wait=False)
70      m.SetUsbPassthrough(1)
71      m.SetVoltage(3.8)
72      m.SetMaxCurrent(8)
73      logging.warn("""
74Monsoon power monitor detected, but no Android devices.
75
76The Monsoon's power output has been enabled. Please now ensure that:
77
78  1. The Monsoon's front and back USB are connected to the host.
79  2. The device is connected to the Monsoon's main and USB channels.
80  3. The device is turned on.
81
82Waiting for device...
83""")
84      util.WaitFor(_ListSerialsOfHealthyOnlineDevices(blacklist), 600)
85      device_serials = _ListSerialsOfHealthyOnlineDevices(blacklist)
86    except IOError:
87      return []
88
89  preferred_device = os.environ.get('ANDROID_SERIAL')
90  if preferred_device in device_serials:
91    logging.warn(
92        'ANDROID_SERIAL is defined. Put %s in the first of the'
93        'discovered devices list.' % preferred_device)
94    device_serials.remove(preferred_device)
95    device_serials.insert(0, preferred_device)
96  return device_serials
97
98
99def GetDevice(finder_options):
100  """Return a Platform instance for the device specified by |finder_options|."""
101  android_platform_options = finder_options.remote_platform_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 android_platform_options.android_blacklist_file:
108    blacklist = device_blacklist.Blacklist(
109        android_platform_options.android_blacklist_file)
110  else:
111    blacklist = None
112
113  if (android_platform_options.device
114      and android_platform_options.device in GetDeviceSerials(blacklist)):
115    return AndroidDevice(
116        android_platform_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
131def _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
151def CanDiscoverDevices():
152  """Returns true if devices are discoverable via adb."""
153  if not _HasValidAdb():
154    return False
155
156  try:
157    device_utils.DeviceUtils.HealthyDevices(None)
158    return True
159  except (device_errors.CommandFailedError, device_errors.CommandTimeoutError,
160          device_errors.NoAdbError, OSError):
161    return False
162
163
164def FindAllAvailableDevices(options):
165  """Returns a list of available devices.
166  """
167  # Disable Android device discovery when remote testing a CrOS device
168  if options.cros_remote:
169    return []
170
171  android_platform_options = options.remote_platform_options
172  devices = []
173  try:
174    if CanDiscoverDevices():
175      blacklist = None
176      if android_platform_options.android_blacklist_file:
177        blacklist = device_blacklist.Blacklist(
178            android_platform_options.android_blacklist_file)
179      devices = AndroidDevice.GetAllConnectedDevices(blacklist)
180  finally:
181    if not devices and _HasValidAdb():
182      try:
183        adb_wrapper.AdbWrapper.KillServer()
184      except device_errors.NoAdbError as e:
185        logging.warning(
186            'adb reported as present, but NoAdbError thrown: %s', str(e))
187
188  return devices
189