Home | History | Annotate | Download | only in at-factory-tool
      1 # !/usr/bin/python
      2 # Copyright 2017 Google Inc. All Rights Reserved.
      3 # Author: shanyu (at] google.com (Yu Shan)
      4 #
      5 # Licensed under the Apache License, Version 2.0 (the "License");
      6 # you may not use this file except in compliance with the License.
      7 # You may obtain a copy of the License at
      8 #
      9 #     http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 # Unless required by applicable law or agreed to in writing, software
     12 # distributed under the License is distributed on an "AS IS" BASIS,
     13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 # See the License for the specific language governing permissions and
     15 # limitations under the License.
     16 
     17 """Fastboot Interface Implementation using sh library."""
     18 import os
     19 import sys
     20 import threading
     21 
     22 import fastboot_exceptions
     23 import sh
     24 
     25 
     26 def _GetCurrentPath():
     27   if getattr(sys, 'frozen', False):
     28     # we are running in a bundle
     29     path = sys._MEIPASS  # pylint: disable=protected-access
     30   else:
     31     # we are running in a normal Python environment
     32     path = os.path.dirname(os.path.abspath(__file__))
     33   return path
     34 
     35 
     36 class FastbootDevice(object):
     37   """An abstracted fastboot device object.
     38 
     39   Attributes:
     40     serial_number: The serial number of the fastboot device.
     41   """
     42   current_path = _GetCurrentPath()
     43   fastboot_command = sh.Command(os.path.join(current_path, 'fastboot'))
     44   HOST_OS = 'Linux'
     45 
     46   @staticmethod
     47   def ListDevices():
     48     """List all fastboot devices.
     49 
     50     Returns:
     51       A list of serial numbers for all the fastboot devices.
     52     """
     53     try:
     54       out = FastbootDevice.fastboot_command('devices')
     55       device_serial_numbers = out.replace('\tfastboot', '').rstrip().split('\n')
     56       # filter out empty string
     57       return filter(None, device_serial_numbers)
     58     except sh.ErrorReturnCode as e:
     59       raise fastboot_exceptions.FastbootFailure(e.stderr)
     60 
     61   def __init__(self, serial_number):
     62     """Initiate the fastboot device object.
     63 
     64     Args:
     65       serial_number: The serial number of the fastboot device.
     66     """
     67     self.serial_number = serial_number
     68     # Lock to make sure only one fastboot command can be issued to one device
     69     # at one time.
     70     self._lock = threading.Lock()
     71 
     72   def Reboot(self):
     73     """Reboot the device into fastboot mode.
     74 
     75     Returns:
     76       The command output.
     77     """
     78     try:
     79       self._lock.acquire()
     80       out = self.fastboot_command('-s', self.serial_number, 'reboot-bootloader')
     81       return out
     82     except sh.ErrorReturnCode as e:
     83       raise fastboot_exceptions.FastbootFailure(e.stderr)
     84     finally:
     85       self._lock.release()
     86 
     87   def Oem(self, oem_command, err_to_out):
     88     """Run an OEM command.
     89 
     90     Args:
     91       oem_command: The OEM command to run.
     92       err_to_out: Whether to redirect stderr to stdout.
     93     Returns:
     94       The result message for the OEM command.
     95     Raises:
     96       FastbootFailure: If failure happens during the command.
     97     """
     98     try:
     99       self._lock.acquire()
    100       out = self.fastboot_command(
    101           '-s', self.serial_number, 'oem', oem_command, _err_to_out=err_to_out)
    102       return out
    103     except sh.ErrorReturnCode as e:
    104       if err_to_out:
    105         err = e.stdout
    106       else:
    107         err = e.stderr
    108       raise fastboot_exceptions.FastbootFailure(err)
    109     finally:
    110       self._lock.release()
    111 
    112   def Flash(self, partition, file_path):
    113     """Flash a file to a partition.
    114 
    115     Args:
    116       file_path: The partition file to be flashed.
    117       partition: The partition to be flashed.
    118     Returns:
    119       The output for the fastboot command required.
    120     Raises:
    121       FastbootFailure: If failure happens during the command.
    122     """
    123     try:
    124       self._lock.acquire()
    125       out = self.fastboot_command(
    126           '-s', self.serial_number, 'flash', partition, file_path)
    127       return out
    128     except sh.ErrorReturnCode as e:
    129       raise fastboot_exceptions.FastbootFailure(e.stderr)
    130     finally:
    131       self._lock.release()
    132 
    133   def Upload(self, file_path):
    134     """Pulls a file from the fastboot device to the local file system.
    135 
    136     Args:
    137       file_path: The file path of the file system
    138         that the remote file would be pulled to.
    139     Returns:
    140       The output for the fastboot command required.
    141     Raises:
    142       FastbootFailure: If failure happens during the command.
    143     """
    144     try:
    145       self._lock.acquire()
    146       out = self.fastboot_command('-s', self.serial_number, 'get_staged',
    147                                   file_path)
    148       return out
    149     except sh.ErrorReturnCode as e:
    150       raise fastboot_exceptions.FastbootFailure(e.stderr)
    151     finally:
    152       self._lock.release()
    153 
    154   def Download(self, file_path):
    155     """Push a file from the file system to the fastboot device.
    156 
    157     Args:
    158       file_path: The file path of the file on the local file system
    159         that would be pushed to fastboot device.
    160     Returns:
    161       The output for the fastboot command required.
    162     Raises:
    163       FastbootFailure: If failure happens during the command.
    164     """
    165     try:
    166       self._lock.acquire()
    167       out = self.fastboot_command('-s', self.serial_number, 'stage', file_path)
    168       return out
    169     except sh.ErrorReturnCode as e:
    170       raise fastboot_exceptions.FastbootFailure(e.stderr)
    171     finally:
    172       self._lock.release()
    173 
    174   def GetVar(self, var):
    175     """Get a variable from the device.
    176 
    177     Note that the return value is in stderr instead of stdout.
    178     Args:
    179       var: The name of the variable.
    180     Returns:
    181       The value for the variable.
    182     Raises:
    183       FastbootFailure: If failure happens during the command.
    184     """
    185     try:
    186       self._lock.acquire()
    187       # Fastboot getvar command's output would be in stderr instead of stdout.
    188       # Need to redirect stderr to stdout.
    189       out = self.fastboot_command(
    190           '-s', self.serial_number, 'getvar', var, _err_to_out=True)
    191     except sh.ErrorReturnCode as e:
    192       # Since we redirected stderr, we should print stdout here.
    193       raise fastboot_exceptions.FastbootFailure(e.stdout)
    194     finally:
    195       self._lock.release()
    196     if var == 'at-vboot-state':
    197       # For the result of vboot-state, it does not follow the standard.
    198       return out
    199     lines = out.split('\n')
    200     for line in lines:
    201       if line.startswith(var + ': '):
    202         value = line.replace(var + ': ', '')
    203     return value
    204 
    205   @staticmethod
    206   def GetHostOs():
    207     return FastbootDevice.HOST_OS
    208 
    209   def Disconnect(self):
    210     """Disconnect from the fastboot device."""
    211     pass
    212 
    213   def __del__(self):
    214     self.Disconnect()
    215