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. 4import logging 5import os 6import re 7import subprocess 8 9from telemetry.core import util 10from telemetry.internal.platform import cros_device 11from telemetry.internal.platform import device 12from telemetry.internal.platform.profiler import monsoon 13 14from devil.android import device_blacklist 15from devil.android import device_errors 16from devil.android import device_utils 17from devil.android.sdk import adb_wrapper 18 19 20class 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 50def _ListSerialsOfHealthyOnlineDevices(blacklist): 51 return [d.adb.GetDeviceSerial() 52 for d in device_utils.DeviceUtils.HealthyDevices(blacklist) 53 if d.IsOnline()] 54 55 56def 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(""" 75Monsoon power monitor detected, but no Android devices. 76 77The 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 83Waiting 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 100def 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 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 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 181def 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