1# Copyright 2015 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"""This module wraps Android's fastboot tool. 5 6This is a thin wrapper around the fastboot interface. Any additional complexity 7should be delegated to a higher level (ex. FastbootUtils). 8""" 9# pylint: disable=unused-argument 10 11from devil import devil_env 12from devil.android import decorators 13from devil.android import device_errors 14from devil.utils import cmd_helper 15from devil.utils import lazy 16 17_DEFAULT_TIMEOUT = 30 18_DEFAULT_RETRIES = 3 19_FLASH_TIMEOUT = _DEFAULT_TIMEOUT * 10 20 21 22class Fastboot(object): 23 24 _fastboot_path = lazy.WeakConstant(lambda: devil_env.config.FetchPath( 25 'fastboot')) 26 27 def __init__(self, 28 device_serial, 29 default_timeout=_DEFAULT_TIMEOUT, 30 default_retries=_DEFAULT_RETRIES): 31 """Initializes the FastbootWrapper. 32 33 Args: 34 device_serial: The device serial number as a string. 35 """ 36 if not device_serial: 37 raise ValueError('A device serial must be specified') 38 self._device_serial = str(device_serial) 39 self._default_timeout = default_timeout 40 self._default_retries = default_retries 41 42 def __str__(self): 43 return self._device_serial 44 45 @classmethod 46 def _RunFastbootCommand(cls, cmd): 47 """Run a generic fastboot command. 48 49 Args: 50 cmd: Command to run. Must be list of args, the first one being the command 51 52 Returns: 53 output of command. 54 55 Raises: 56 TypeError: If cmd is not of type list. 57 """ 58 if isinstance(cmd, list): 59 cmd = [cls._fastboot_path.read()] + cmd 60 else: 61 raise TypeError('Command for _RunDeviceFastbootCommand must be a list.') 62 # fastboot can't be trusted to keep non-error output out of stderr, so 63 # capture stderr as part of stdout. 64 status, output = cmd_helper.GetCmdStatusAndOutput(cmd, merge_stderr=True) 65 if int(status) != 0: 66 raise device_errors.FastbootCommandFailedError(cmd, output, status) 67 return output 68 69 def _RunDeviceFastbootCommand(self, cmd): 70 """Run a fastboot command on the device associated with this object. 71 72 Args: 73 cmd: Command to run. Must be list of args, the first one being the command 74 75 Returns: 76 output of command. 77 78 Raises: 79 TypeError: If cmd is not of type list. 80 """ 81 if isinstance(cmd, list): 82 cmd = ['-s', self._device_serial] + cmd 83 return self._RunFastbootCommand(cmd) 84 85 @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 86 def GetVar(self, variable, timeout=None, retries=None): 87 args = ['getvar', variable] 88 output = self._RunDeviceFastbootCommand(args) 89 # getvar returns timing information on the last line of output, so only 90 # parse the first line. 91 output = output.splitlines()[0] 92 # And the first line should match the format '$(var): $(value)'. 93 if variable + ': ' not in output: 94 raise device_errors.FastbootCommandFailedError( 95 args, output, message="Unknown 'getvar' output format.") 96 return output.split('%s: ' % variable)[1].strip() 97 98 @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0) 99 def Flash(self, partition, image, timeout=None, retries=None): 100 """Flash partition with img. 101 102 Args: 103 partition: Partition to be flashed. 104 image: location of image to flash with. 105 """ 106 self._RunDeviceFastbootCommand(['flash', partition, image]) 107 108 @classmethod 109 @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 110 def Devices(cls, timeout=None, retries=None): 111 """Outputs list of devices in fastboot mode. 112 113 Returns: 114 List of Fastboot objects, one for each device in fastboot. 115 """ 116 output = cls._RunFastbootCommand(['devices']) 117 return [Fastboot(line.split()[0]) for line in output.splitlines()] 118 119 @decorators.WithTimeoutAndRetriesFromInstance() 120 def RebootBootloader(self, timeout=None, retries=None): 121 """Reboot from fastboot, into fastboot.""" 122 self._RunDeviceFastbootCommand(['reboot-bootloader']) 123 124 @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0) 125 def Reboot(self, timeout=None, retries=None): 126 """Reboot from fastboot to normal usage""" 127 self._RunDeviceFastbootCommand(['reboot']) 128 129 @decorators.WithTimeoutAndRetriesFromInstance() 130 def SetOemOffModeCharge(self, value, timeout=None, retries=None): 131 """Sets off mode charging 132 133 Args: 134 value: boolean value to set off-mode-charging on or off. 135 """ 136 self._RunDeviceFastbootCommand(['oem', 'off-mode-charge', str(int(value))]) 137