Home | History | Annotate | Download | only in at-factory-tool
      1 #!/usr/bin/python
      2 # -*- coding: utf-8 -*-
      3 # Copyright 2017 The Android Open Source Project
      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 """AT-Factory-Tool manager module.
     18 
     19 This module provides the logical implementation of the graphical tool for
     20 managing the ATFA and AT communication.
     21 """
     22 import base64
     23 from datetime import datetime
     24 import json
     25 import os
     26 import re
     27 import tempfile
     28 import threading
     29 import uuid
     30 
     31 from fastboot_exceptions import DeviceNotFoundException
     32 from fastboot_exceptions import FastbootFailure
     33 from fastboot_exceptions import NoAlgorithmAvailableException
     34 from fastboot_exceptions import ProductAttributesFileFormatError
     35 from fastboot_exceptions import ProductNotSpecifiedException
     36 
     37 BOOTLOADER_STRING = '(bootloader) '
     38 
     39 
     40 class EncryptionAlgorithm(object):
     41   """The support encryption algorithm constant."""
     42   ALGORITHM_P256 = 1
     43   ALGORITHM_CURVE25519 = 2
     44 
     45 
     46 class ProvisionStatus(object):
     47   """The provision status constant."""
     48   _PROCESSING        = 0
     49   _SUCCESS           = 1
     50   _FAILED            = 2
     51 
     52   IDLE              = 0
     53   WAITING           = 1
     54   FUSEVBOOT_ING     = (10 + _PROCESSING)
     55   FUSEVBOOT_SUCCESS = (10 + _SUCCESS)
     56   FUSEVBOOT_FAILED  = (10 + _FAILED)
     57   REBOOT_ING        = (20 + _PROCESSING)
     58   REBOOT_SUCCESS    = (20 + _SUCCESS)
     59   REBOOT_FAILED     = (20 + _FAILED)
     60   FUSEATTR_ING      = (30 + _PROCESSING)
     61   FUSEATTR_SUCCESS  = (30 + _SUCCESS)
     62   FUSEATTR_FAILED   = (30 + _FAILED)
     63   LOCKAVB_ING       = (40 + _PROCESSING)
     64   LOCKAVB_SUCCESS   = (40 + _SUCCESS)
     65   LOCKAVB_FAILED    = (40 + _FAILED)
     66   PROVISION_ING     = (50 + _PROCESSING)
     67   PROVISION_SUCCESS = (50 + _SUCCESS)
     68   PROVISION_FAILED  = ( + _FAILED)
     69 
     70   STRING_MAP = {
     71     IDLE              : ['Idle', ''],
     72     WAITING           : ['Waiting', ''],
     73     FUSEVBOOT_ING     : ['Fusing Bootloader Vboot Key...', '...'],
     74     FUSEVBOOT_SUCCESS : ['Bootloader Locked', ''],
     75     FUSEVBOOT_FAILED  : ['Fuse Bootloader Vboot Key Failed', ''],
     76     REBOOT_ING        : ['Rebooting Device To Check Vboot Key...',
     77                          '...'],
     78     REBOOT_SUCCESS    : ['Bootloader Verified Boot Checked', ''],
     79     REBOOT_FAILED     : ['Reboot Device Failed', ''],
     80     FUSEATTR_ING      : ['Fusing Permanent Attributes', '...'],
     81     FUSEATTR_SUCCESS  : ['Permanent Attributes Fused', ''],
     82     FUSEATTR_FAILED   : ['Fuse Permanent Attributes Failed', ''],
     83     LOCKAVB_ING       : ['Locking Android Verified Boot', 'AVB...'],
     84     LOCKAVB_SUCCESS   : ['Android Verified Boot Locked', 'AVB'],
     85     LOCKAVB_FAILED    : ['Lock Android Verified Boot Failed', 'AVB'],
     86     PROVISION_ING     : ['Provisioning Attestation Key', '...'],
     87     PROVISION_SUCCESS : ['Attestation Key Provisioned', ''],
     88     PROVISION_FAILED  : ['Provision Attestation Key Failed', '']
     89 
     90   }
     91 
     92   @staticmethod
     93   def ToString(provision_status, language_index):
     94     return ProvisionStatus.STRING_MAP[provision_status][language_index]
     95 
     96   @staticmethod
     97   def isSuccess(provision_status):
     98     return provision_status % 10 == ProvisionStatus._SUCCESS
     99 
    100   @staticmethod
    101   def isProcessing(provision_status):
    102     return provision_status % 10 == ProvisionStatus._PROCESSING
    103 
    104   @staticmethod
    105   def isFailed(provision_status):
    106     return provision_status % 10 == ProvisionStatus._FAILED
    107 
    108 
    109 class ProvisionState(object):
    110   """The provision state of the target device."""
    111   bootloader_locked = False
    112   avb_perm_attr_set = False
    113   avb_locked = False
    114   provisioned = False
    115 
    116 
    117 class ProductInfo(object):
    118   """The information about a product.
    119 
    120   Attributes:
    121     product_id: The id for the product.
    122     product_name: The name for the product.
    123     product_attributes: The byte array of the product permanent attributes.
    124   """
    125 
    126   def __init__(self, product_id, product_name, product_attributes, vboot_key):
    127     self.product_id = product_id
    128     self.product_name = product_name
    129     self.product_attributes = product_attributes
    130     self.vboot_key = vboot_key
    131 
    132 
    133 class DeviceInfo(object):
    134   """The class to wrap the information about a fastboot device.
    135 
    136   Attributes:
    137     serial_number: The serial number for the device.
    138     location: The physical USB location for the device.
    139   """
    140 
    141   def __init__(self, _fastboot_device_controller, serial_number,
    142                location=None, provision_status=ProvisionStatus.IDLE,
    143                provision_state=ProvisionState()):
    144     self._fastboot_device_controller = _fastboot_device_controller
    145     self.serial_number = serial_number
    146     self.location = location
    147     # The provision status and provision state is only meaningful for target
    148     # device.
    149     self.provision_status = provision_status
    150     self.provision_state = provision_state
    151     # The number of attestation keys left for the selected product. This
    152     # attribute is only meaning for ATFA device.
    153     self.keys_left = None
    154 
    155   def Copy(self):
    156     return DeviceInfo(None, self.serial_number, self.location,
    157                       self.provision_status)
    158 
    159   def Reboot(self):
    160     return self._fastboot_device_controller.Reboot()
    161 
    162   def Oem(self, oem_command, err_to_out=False):
    163     return self._fastboot_device_controller.Oem(oem_command, err_to_out)
    164 
    165   def Flash(self, partition, file_path):
    166     return self._fastboot_device_controller.Flash(partition, file_path)
    167 
    168   def Upload(self, file_path):
    169     return self._fastboot_device_controller.Upload(file_path)
    170 
    171   def Download(self, file_path):
    172     return self._fastboot_device_controller.Download(file_path)
    173 
    174   def GetVar(self, var):
    175     return self._fastboot_device_controller.GetVar(var)
    176 
    177   def __eq__(self, other):
    178     return (self.serial_number == other.serial_number and
    179             self.location == other.location and
    180             self.provision_status == other.provision_status)
    181 
    182   def __ne__(self, other):
    183     return not self.__eq__(other)
    184 
    185   def __str__(self):
    186     if self.location:
    187       return self.serial_number + ' at location: ' + self.location
    188     else:
    189       return self.serial_number
    190 
    191 
    192 class RebootCallback(object):
    193   """The class to handle reboot success and timeout callbacks."""
    194 
    195   def __init__(
    196       self, timeout, success_callback, timeout_callback):
    197     """Initiate a reboot callback handler class.
    198 
    199     Args:
    200       timeout: How much time to wait for the device to reappear.
    201       success_callback: The callback to be called if the device reappear
    202         before timeout.
    203       timeout_callback: The callback to be called if the device doesn't reappear
    204         before timeout.
    205     """
    206     self.success = success_callback
    207     self.fail = timeout_callback
    208     # Lock to make sure only one callback is called. (either success or timeout)
    209     # This lock can only be obtained once.
    210     self.lock = threading.Lock()
    211     self.timer = threading.Timer(timeout, self._TimeoutCallback)
    212     self.timer.start()
    213 
    214   def _TimeoutCallback(self):
    215     """The function to handle timeout callback.
    216 
    217     Call the timeout_callback that is registered.
    218     """
    219     if self.lock and self.lock.acquire(False):
    220       self.fail()
    221 
    222   def Release(self):
    223     lock = self.lock
    224     timer = self.timer
    225     self.lock = None
    226     self.timer = None
    227     lock.release()
    228     timer.cancel()
    229 
    230 
    231 class AtftManager(object):
    232   """The manager to implement ATFA tasks.
    233 
    234   Attributes:
    235     atfa_dev: A FastbootDevice object identifying the detected ATFA device.
    236     target_dev: A FastbootDevice object identifying the AT device
    237       to be provisioned.
    238   """
    239   SORT_BY_SERIAL = 0
    240   SORT_BY_LOCATION = 1
    241   # The length of the permanent attribute should be 1052.
    242   EXPECTED_ATTRIBUTE_LENGTH = 1052
    243 
    244   # The Permanent Attribute File JSON Key Names:
    245   JSON_PRODUCT_NAME = 'productName'
    246   JSON_PRODUCT_ATTRIBUTE = 'productPermanentAttribute'
    247   JSON_PRODUCT_ATTRIBUTE = 'productPermanentAttribute'
    248   JSON_VBOOT_KEY = 'bootloaderPublicKey'
    249 
    250   def __init__(self, fastboot_device_controller, serial_mapper, configs):
    251     """Initialize attributes and store the supplied fastboot_device_controller.
    252 
    253     Args:
    254       fastboot_device_controller:
    255         The interface to interact with a fastboot device.
    256       serial_mapper:
    257         The interface to get the USB physical location to serial number map.
    258       configs:
    259         The additional configurations. Need to contain 'ATFA_REBOOT_TIMEOUT'.
    260     """
    261     # The timeout period for ATFA device reboot.
    262     self.ATFA_REBOOT_TIMEOUT = 30
    263     if configs and 'ATFA_REBOOT_TIMEOUT' in configs:
    264       try:
    265         self.ATFA_REBOOT_TIMEOUT = float(configs['ATFA_REBOOT_TIMEOUT'])
    266       except ValueError:
    267         pass
    268 
    269     # The serial numbers for the devices that are at least seen twice.
    270     self.stable_serials = []
    271     # The serail numbers for the devices that are only seen once.
    272     self.pending_serials = []
    273     # The atfa device DeviceInfo object.
    274     self.atfa_dev = None
    275     # The atfa device currently rebooting to set the os.
    276     self._atfa_dev_setting = None
    277     # The list of target devices DeviceInfo objects.
    278     self.target_devs = []
    279     # The product information for the selected product.
    280     self.product_info = None
    281      # The atfa device manager.
    282     self._atfa_dev_manager = AtfaDeviceManager(self)
    283     # The fastboot controller.
    284     self._fastboot_device_controller = fastboot_device_controller
    285     # The map mapping serial number to USB location.
    286     self._serial_mapper = serial_mapper()
    287     # The map mapping rebooting device serial number to their reboot callback
    288     # objects.
    289     self._reboot_callbacks = {}
    290 
    291     self._atfa_reboot_lock = threading.Lock()
    292 
    293   def GetATFAKeysLeft(self):
    294     if not self.atfa_dev:
    295       return None
    296     return self.atfa_dev.keys_left
    297 
    298   def CheckATFAStatus(self):
    299     return self._atfa_dev_manager.CheckStatus()
    300 
    301   def SwitchATFAStorage(self):
    302     if self._fastboot_device_controller.GetHostOs() == 'Windows':
    303       # Only windows need to switch. For Linux the partition should already
    304       # mounted.
    305       self._atfa_dev_manager.SwitchStorage()
    306     else:
    307       self.CheckDevice(self.atfa_dev)
    308 
    309   def RebootATFA(self):
    310     return self._atfa_dev_manager.Reboot()
    311 
    312   def ShutdownATFA(self):
    313     return self._atfa_dev_manager.Shutdown()
    314 
    315   def ProcessATFAKey(self):
    316     return self._atfa_dev_manager.ProcessKey()
    317 
    318   def ListDevices(self, sort_by=SORT_BY_LOCATION):
    319     """Get device list.
    320 
    321     Get the serial number of the ATFA device and the target device. If the
    322     device does not exist, the returned serial number would be None.
    323 
    324     Args:
    325       sort_by: The field to sort by.
    326     """
    327     # ListDevices returns a list of USBHandles
    328     device_serials = self._fastboot_device_controller.ListDevices()
    329     self.UpdateDevices(device_serials)
    330     self._HandleRebootCallbacks()
    331     self._SortTargetDevices(sort_by)
    332 
    333   def UpdateDevices(self, device_serials):
    334     """Update device list.
    335 
    336     Args:
    337       device_serials: The device serial numbers.
    338     """
    339     self._UpdateSerials(device_serials)
    340     if not self.stable_serials:
    341       self.target_devs = []
    342       self.atfa_dev = None
    343       return
    344     self._HandleSerials()
    345 
    346   @staticmethod
    347   def _SerialAsKey(device):
    348     return device.serial_number
    349 
    350   @staticmethod
    351   def _LocationAsKey(device):
    352     if device.location is None:
    353       return ''
    354     return device.location
    355 
    356   def _SortTargetDevices(self, sort_by):
    357     """Sort the target device list according to sort_by field.
    358 
    359     Args:
    360       sort_by: The field to sort by, possible values are:
    361         self.SORT_BY_LOCATION and self.SORT_BY_SERIAL.
    362     """
    363     if sort_by == self.SORT_BY_LOCATION:
    364       self.target_devs.sort(key=AtftManager._LocationAsKey)
    365     elif sort_by == self.SORT_BY_SERIAL:
    366       self.target_devs.sort(key=AtftManager._SerialAsKey)
    367 
    368   def _UpdateSerials(self, device_serials):
    369     """Update the stored pending_serials and stable_serials.
    370 
    371     Note that we cannot check status once the fastboot device is found since the
    372     device may not be ready yet. So we put the new devices into the pending
    373     state. Once we see the device again in the next refresh, we add that device.
    374     If that device is not seen in the next refresh, we remove it from pending.
    375     This makes sure that the device would have a refresh interval time after
    376     it's recognized as a fastboot device until it's issued command.
    377 
    378     Args:
    379       device_serials: The list of serial numbers of the fastboot devices.
    380     """
    381     stable_serials_copy = self.stable_serials[:]
    382     pending_serials_copy = self.pending_serials[:]
    383     self.stable_serials = []
    384     self.pending_serials = []
    385     for serial in device_serials:
    386       if serial in stable_serials_copy or serial in pending_serials_copy:
    387         # Was in stable or pending state, seen twice, add to stable state.
    388         self.stable_serials.append(serial)
    389       else:
    390         # First seen, add to pending state.
    391         self.pending_serials.append(serial)
    392 
    393   def _CheckAtfaSetOs(self):
    394     """Check whether the ATFA device reappear after a 'set-os' command.
    395 
    396     If it reappears, we create a new ATFA device object.
    397     If not, something wrong happens, we need to clean the rebooting state.
    398     """
    399     atfa_serial = self._atfa_dev_setting.serial_number
    400     if atfa_serial in self.stable_serials:
    401       # We found the ATFA device again.
    402       self._serial_mapper.refresh_serial_map()
    403       controller = self._fastboot_device_controller(atfa_serial)
    404       location = self._serial_mapper.get_location(atfa_serial)
    405       self.atfa_dev = DeviceInfo(controller, atfa_serial, location)
    406 
    407     # Clean the state
    408     self._atfa_dev_setting = None
    409     self._atfa_reboot_lock.release()
    410 
    411   def _HandleSerials(self):
    412     """Create new devices and remove old devices.
    413 
    414     Add device location information and target device provision status.
    415     """
    416     device_serials = self.stable_serials
    417     new_targets = []
    418     atfa_serial = None
    419     for serial in device_serials:
    420       if not serial:
    421         continue
    422 
    423       if serial.startswith('ATFA'):
    424         atfa_serial = serial
    425       else:
    426         new_targets.append(serial)
    427 
    428     if atfa_serial is None:
    429       # No ATFA device found.
    430       self.atfa_dev = None
    431     elif self.atfa_dev is None or self.atfa_dev.serial_number != atfa_serial:
    432       self._AddNewAtfa(atfa_serial)
    433 
    434     # Remove those devices that are not in new targets and not rebooting.
    435     self.target_devs = [
    436         device for device in self.target_devs
    437         if (device.serial_number in new_targets or
    438             device.provision_status == ProvisionStatus.REBOOT_ING)
    439     ]
    440 
    441     common_serials = [device.serial_number for device in self.target_devs]
    442 
    443     # Create new device object for newly added devices.
    444     self._serial_mapper.refresh_serial_map()
    445     for serial in new_targets:
    446       if serial not in common_serials:
    447         self._CreateNewTargetDevice(serial)
    448 
    449   def _CreateNewTargetDevice(self, serial, check_status=True):
    450     """Create a new target device object.
    451 
    452     Args:
    453       serial: The serial number for the new target device.
    454       check_status: Whether to check provision status for the target device.
    455     """
    456     try:
    457       controller = self._fastboot_device_controller(serial)
    458       location = self._serial_mapper.get_location(serial)
    459 
    460       new_target_dev = DeviceInfo(controller, serial, location)
    461       if check_status:
    462         self.CheckProvisionStatus(new_target_dev)
    463       self.target_devs.append(new_target_dev)
    464     except FastbootFailure as e:
    465       e.msg = ('Error while creating new device: ' + str(new_target_dev) +
    466                '\n'+ e.msg)
    467       self.stable_serials.remove(serial)
    468       raise e
    469 
    470   def _AddNewAtfa(self, atfa_serial):
    471     """Create a new ATFA device object.
    472 
    473     If the OS variable on the ATFA device is not the same as the host OS
    474     version, we would use set the correct OS version.
    475 
    476     Args:
    477       atfa_serial: The serial number of the ATFA device to be added.
    478     """
    479     self._serial_mapper.refresh_serial_map()
    480     controller = self._fastboot_device_controller(atfa_serial)
    481     location = self._serial_mapper.get_location(atfa_serial)
    482     if self._atfa_reboot_lock.acquire(False):
    483       # If there's not an atfa setting os already happening
    484       self._atfa_dev_setting = DeviceInfo(controller, atfa_serial, location)
    485       try:
    486         atfa_os = self._GetOs(self._atfa_dev_setting)
    487       except FastbootFailure:
    488         # The device is not ready for get OS command, we just ignore the device.
    489         self._atfa_reboot_lock.release()
    490         return
    491       host_os = controller.GetHostOs()
    492       if atfa_os == host_os:
    493         # The OS set for the ATFA is correct, we just create the new device.
    494         self.atfa_dev = self._atfa_dev_setting
    495         self._atfa_dev_setting = None
    496         self._atfa_reboot_lock.release()
    497       else:
    498         # The OS set for the ATFA is not correct, need to set it.
    499         try:
    500           self._SetOs(self._atfa_dev_setting, host_os)
    501           # SetOs include a rebooting process, but the device would not
    502           # disappear from the device list immediately after the command.
    503           # We would check if the ATFA reappear after ATFA_REBOOT_TIMEOUT.
    504           timer = threading.Timer(
    505               self.ATFA_REBOOT_TIMEOUT, self._CheckAtfaSetOs)
    506           timer.start()
    507         except FastbootFailure:
    508           self._atfa_dev_setting = None
    509           self._atfa_reboot_lock.release()
    510 
    511   def _SetOs(self, target_dev, os_version):
    512     """Change the os version on the target device.
    513 
    514     Args:
    515       target_dev: The target device.
    516       os_version: The os version to set, options are 'Windows' or 'Linux'.
    517     Raises:
    518       FastbootFailure: when fastboot command fails.
    519     """
    520     target_dev.Oem('set-os ' + os_version)
    521 
    522   def _GetOs(self, target_dev):
    523     """Get the os version of the target device.
    524 
    525     Args:
    526       target_dev: The target deivce.
    527     Returns:
    528       The os version.
    529     Raises:
    530       FastbootFailure: when fastboot command fails.
    531     """
    532     output = target_dev.Oem('get-os', True)
    533     if output and 'Linux' in output:
    534       return 'Linux'
    535     else:
    536       return 'Windows'
    537 
    538   def _HandleRebootCallbacks(self):
    539     """Handle the callback functions after the reboot."""
    540     success_serials = []
    541     for serial in self._reboot_callbacks:
    542       if serial in self.stable_serials:
    543         callback_lock = self._reboot_callbacks[serial].lock
    544         # Make sure the timeout callback would not be called at the same time.
    545         if callback_lock and callback_lock.acquire(False):
    546           success_serials.append(serial)
    547 
    548     for serial in success_serials:
    549       self._reboot_callbacks[serial].success()
    550 
    551   def _ParseStateString(self, state_string):
    552     """Parse the string returned by 'at-vboot-state' to a key-value map.
    553 
    554     Args:
    555       state_string: The string returned by oem at-vboot-state command.
    556 
    557     Returns:
    558       A key-value map.
    559     """
    560     state_map = {}
    561     lines = state_string.splitlines()
    562     for line in lines:
    563       if line.startswith(BOOTLOADER_STRING):
    564         key_value = re.split(r':[\s]*|=', line.replace(BOOTLOADER_STRING, ''))
    565         if len(key_value) == 2:
    566           state_map[key_value[0]] = key_value[1]
    567     return state_map
    568 
    569   def CheckProvisionStatus(self, target_dev):
    570     """Check whether the target device has been provisioned.
    571 
    572     Args:
    573       target_dev: The target device (DeviceInfo).
    574     """
    575     at_attest_uuid = target_dev.GetVar('at-attest-uuid')
    576     state_string = target_dev.GetVar('at-vboot-state')
    577 
    578     target_dev.provision_status = ProvisionStatus.IDLE
    579     target_dev.provision_state = ProvisionState()
    580 
    581     status_set = False
    582 
    583     # TODO(shanyu): We only need empty string here
    584     # NOT_PROVISIONED is for test purpose.
    585     if at_attest_uuid and at_attest_uuid != 'NOT_PROVISIONED':
    586       target_dev.provision_status = ProvisionStatus.PROVISION_SUCCESS
    587       status_set = True
    588       target_dev.provision_state.provisioned = True
    589 
    590     # state_string should be in format:
    591     # (bootloader) bootloader-locked: 1
    592     # (bootloader) bootloader-min-versions: -1,0,3
    593     # (bootloader) avb-perm-attr-set: 1
    594     # (bootloader) avb-locked: 0
    595     # (bootloader) avb-unlock-disabled: 0
    596     # (bootloader) avb-min-versions: 0:1,1:1,2:1,4097 :2,4098:2
    597     if not state_string:
    598       return
    599     state_map = self._ParseStateString(state_string)
    600     if state_map.get('avb-locked') and state_map['avb-locked'] == '1':
    601       if not status_set:
    602         target_dev.provision_status = ProvisionStatus.LOCKAVB_SUCCESS
    603         status_set = True
    604       target_dev.provision_state.avb_locked = True
    605 
    606     if (state_map.get('avb-perm-attr-set') and
    607         state_map['avb-perm-attr-set'] == '1'):
    608       if not status_set:
    609         target_dev.provision_status = ProvisionStatus.FUSEATTR_SUCCESS
    610         status_set = True
    611       target_dev.provision_state.avb_perm_attr_set = True
    612 
    613     if (state_map.get('bootloader-locked') and
    614         state_map['bootloader-locked'] == '1'):
    615       if not status_set:
    616         target_dev.provision_status = ProvisionStatus.FUSEVBOOT_SUCCESS
    617       target_dev.provision_state.bootloader_locked = True
    618 
    619 
    620   def TransferContent(self, src, dst):
    621     """Transfer content from a device to another device.
    622 
    623     Download file from one device and store it into a tmp file. Upload file from
    624     the tmp file onto another device.
    625 
    626     Args:
    627       src: The source device to be copied from.
    628       dst: The destination device to be copied to.
    629     """
    630     # create a tmp folder
    631     tmp_folder = tempfile.mkdtemp()
    632     # temperate file name is a UUID based on host ID and current time.
    633     tmp_file_name = str(uuid.uuid1())
    634     file_path = os.path.join(tmp_folder, tmp_file_name)
    635     # pull file to local fs
    636     src.Upload(file_path)
    637     # push file to fastboot device
    638     dst.Download(file_path)
    639     # delete the temperate file afterwards
    640     if os.path.exists(file_path):
    641       os.remove(file_path)
    642     # delete the temperate folder afterwards
    643     if os.path.exists(tmp_folder):
    644       os.rmdir(tmp_folder)
    645 
    646   def GetTargetDevice(self, serial):
    647     """Get the target DeviceInfo object according to the serial number.
    648 
    649     Args:
    650       serial: The serial number for the device object.
    651     Returns:
    652       The DeviceInfo object for the device. None if not exists.
    653     """
    654     for device in self.target_devs:
    655       if device.serial_number == serial:
    656         return device
    657 
    658     return None
    659 
    660   def Provision(self, target):
    661     """Provision the key to the target device.
    662 
    663     1. Get supported encryption algorithm
    664     2. Send atfa-start-provisioning message to ATFA
    665     3. Transfer content from ATFA to target
    666     4. Send at-get-ca-request to target
    667     5. Transfer content from target to ATFA
    668     6. Send atfa-finish-provisioning message to ATFA
    669     7. Transfer content from ATFA to target
    670     8. Send at-set-ca-response message to target
    671 
    672     Args:
    673       target: The target device to be provisioned to.
    674     """
    675     try:
    676       target.provision_status = ProvisionStatus.PROVISION_ING
    677       atfa = self.atfa_dev
    678       AtftManager.CheckDevice(atfa)
    679       # Set the ATFA's time first.
    680       self._atfa_dev_manager.SetTime()
    681       algorithm_list = self._GetAlgorithmList(target)
    682       algorithm = self._ChooseAlgorithm(algorithm_list)
    683       # First half of the DH key exchange
    684       atfa.Oem('atfa-start-provisioning ' + str(algorithm))
    685       self.TransferContent(atfa, target)
    686       # Second half of the DH key exchange
    687       target.Oem('at-get-ca-request')
    688       self.TransferContent(target, atfa)
    689       # Encrypt and transfer key bundle
    690       atfa.Oem('atfa-finish-provisioning')
    691       self.TransferContent(atfa, target)
    692       # Provision the key on device
    693       target.Oem('at-set-ca-response')
    694 
    695       # After a success provision, the status should be updated.
    696       self.CheckProvisionStatus(target)
    697       if not target.provision_state.provisioned:
    698         raise FastbootFailure('Status not updated.')
    699     except (FastbootFailure, DeviceNotFoundException) as e:
    700       target.provision_status = ProvisionStatus.PROVISION_FAILED
    701       raise e
    702 
    703   def FuseVbootKey(self, target):
    704     """Fuse the verified boot key to the target device.
    705 
    706     Args:
    707       target: The target device.
    708     """
    709     if not self.product_info:
    710       target.provision_status = ProvisionStatus.FUSEVBOOT_FAILED
    711       raise ProductNotSpecifiedException
    712 
    713     # Create a temporary file to store the vboot key.
    714     target.provision_status = ProvisionStatus.FUSEVBOOT_ING
    715     try:
    716       temp_file = tempfile.NamedTemporaryFile(delete=False)
    717       temp_file.write(self.product_info.vboot_key)
    718       temp_file.close()
    719       temp_file_name = temp_file.name
    720       target.Download(temp_file_name)
    721       # Delete the temporary file.
    722       os.remove(temp_file_name)
    723       target.Oem('fuse at-bootloader-vboot-key')
    724 
    725       # After a success fuse, the status should be updated.
    726       self.CheckProvisionStatus(target)
    727       if not target.provision_state.bootloader_locked:
    728         raise FastbootFailure('Status not updated.')
    729 
    730       # # Another possible flow:
    731       # target.Flash('sec', temp_file_name)
    732       # os.remove(temp_file_name)
    733     except FastbootFailure as e:
    734       target.provision_status = ProvisionStatus.FUSEVBOOT_FAILED
    735       raise e
    736 
    737   def FusePermAttr(self, target):
    738     """Fuse the permanent attributes to the target device.
    739 
    740     Args:
    741       target: The target device.
    742     """
    743     if not self.product_info:
    744       target.provision_status = ProvisionStatus.FUSEATTR_FAILED
    745       raise ProductNotSpecifiedException
    746     try:
    747       target.provision_status = ProvisionStatus.FUSEATTR_ING
    748       temp_file = tempfile.NamedTemporaryFile(delete=False)
    749       temp_file.write(self.product_info.product_attributes)
    750       temp_file.close()
    751       temp_file_name = temp_file.name
    752       target.Download(temp_file_name)
    753       os.remove(temp_file_name)
    754       target.Oem('fuse at-perm-attr')
    755 
    756       self.CheckProvisionStatus(target)
    757       if not target.provision_state.avb_perm_attr_set:
    758         raise FastbootFailure('Status not updated')
    759 
    760     except FastbootFailure as e:
    761       target.provision_status = ProvisionStatus.FUSEATTR_FAILED
    762       raise e
    763 
    764   def LockAvb(self, target):
    765     """Lock the android verified boot for the target.
    766 
    767     Args:
    768       target: The target device.
    769     """
    770     try:
    771       target.provision_status = ProvisionStatus.LOCKAVB_ING
    772       target.Oem('at-lock-vboot')
    773       self.CheckProvisionStatus(target)
    774       if not target.provision_state.avb_locked:
    775         raise FastbootFailure('Status not updated')
    776     except FastbootFailure as e:
    777       target.provision_status = ProvisionStatus.LOCKAVB_FAILED
    778       raise e
    779 
    780   def Reboot(self, target, timeout, success_callback, timeout_callback):
    781     """Reboot the target device.
    782 
    783     Args:
    784       target: The target device.
    785       timeout: The time out value.
    786       success_callback: The callback function called when the device reboots
    787         successfully.
    788       timeout_callback: The callback function called when the device reboots
    789         timeout.
    790 
    791     The device would disappear from the list after reboot.
    792     If we see the device again within timeout, call the success_callback,
    793     otherwise call the timeout_callback.
    794     """
    795     try:
    796       target.Reboot()
    797       serial = target.serial_number
    798       location = target.location
    799       # We assume after the reboot the device would disappear
    800       self.target_devs.remove(target)
    801       del target
    802       self.stable_serials.remove(serial)
    803       # Create a rebooting target device that only contains serial and location.
    804       rebooting_target = DeviceInfo(None, serial, location)
    805       rebooting_target.provision_status = ProvisionStatus.REBOOT_ING
    806       self.target_devs.append(rebooting_target)
    807 
    808       reboot_callback = RebootCallback(
    809           timeout,
    810           self.RebootCallbackWrapper(success_callback, serial, True),
    811           self.RebootCallbackWrapper(timeout_callback, serial, False))
    812       self._reboot_callbacks[serial] = reboot_callback
    813 
    814     except FastbootFailure as e:
    815       target.provision_status = ProvisionStatus.REBOOT_FAILED
    816       raise e
    817 
    818   def RebootCallbackWrapper(self, callback, serial, success):
    819     """This wrapper function wraps the original callback function.
    820 
    821     Some clean up operations are added. We need to remove the handler if
    822     callback is called. We need to release the resource the handler requires.
    823     We also needs to remove the rebooting device from the target list since a
    824     new device would be created if the device reboot successfully.
    825 
    826     Args:
    827       callback: The original callback function.
    828       serial: The serial number for the device.
    829       success: Whether this is the success callback.
    830     Returns:
    831       An extended callback function.
    832     """
    833     def RebootCallbackFunc(callback=callback, serial=serial, success=success):
    834       try:
    835         rebooting_dev = self.GetTargetDevice(serial)
    836         if rebooting_dev:
    837           self.target_devs.remove(rebooting_dev)
    838           del rebooting_dev
    839         if success:
    840           self._serial_mapper.refresh_serial_map()
    841           self._CreateNewTargetDevice(serial, True)
    842           self.GetTargetDevice(serial).provision_status = (
    843               ProvisionStatus.REBOOT_SUCCESS)
    844         callback()
    845         self._reboot_callbacks[serial].Release()
    846         del self._reboot_callbacks[serial]
    847       except FastbootFailure as e:
    848         # Release the lock so that it can be obtained again.
    849         self._reboot_callbacks[serial].lock.release()
    850         raise e
    851 
    852 
    853 
    854     return RebootCallbackFunc
    855 
    856   def _GetAlgorithmList(self, target):
    857     """Get the supported algorithm list.
    858 
    859     Get the available algorithm list using getvar at-attest-dh
    860     at_attest_dh should be in format 1:p256,2:curve25519
    861     or 1:p256
    862     or 2:curve25519.
    863 
    864     Args:
    865       target: The target device to check for supported algorithm.
    866     Returns:
    867       A list of available algorithms.
    868       Options are ALGORITHM_P256 or ALGORITHM_CURVE25519
    869     """
    870     at_attest_dh = target.GetVar('at-attest-dh')
    871     algorithm_strings = at_attest_dh.split(',')
    872     algorithm_list = []
    873     for algorithm_string in algorithm_strings:
    874       algorithm_list.append(int(algorithm_string.split(':')[0]))
    875     return algorithm_list
    876 
    877   def _ChooseAlgorithm(self, algorithm_list):
    878     """Choose the encryption algorithm to use for key provisioning.
    879 
    880     We favor ALGORITHM_CURVE25519 over ALGORITHM_P256
    881 
    882     Args:
    883       algorithm_list: The list containing all available algorithms.
    884     Returns:
    885       The selected available algorithm
    886     Raises:
    887       NoAlgorithmAvailableException:
    888         When there's no available valid algorithm to use.
    889     """
    890     if not algorithm_list:
    891       raise NoAlgorithmAvailableException()
    892     if EncryptionAlgorithm.ALGORITHM_CURVE25519 in algorithm_list:
    893       return EncryptionAlgorithm.ALGORITHM_CURVE25519
    894     elif EncryptionAlgorithm.ALGORITHM_P256 in algorithm_list:
    895       return EncryptionAlgorithm.ALGORITHM_P256
    896 
    897     raise NoAlgorithmAvailableException()
    898 
    899   def ProcessProductAttributesFile(self, content):
    900     """Process the product attributes file.
    901 
    902     The file should follow the following JSON format:
    903       {
    904         "productName": "",
    905         "productDescription": "",
    906         "productConsoleId": "",
    907         "productPermanentAttribute": "",
    908         "bootloaderPublicKey": "",
    909         "creationTime": ""
    910       }
    911 
    912     Args:
    913       content: The content of the product attributes file.
    914     Raises:
    915       ProductAttributesFileFormatError: When the file format is wrong.
    916     """
    917     try:
    918       file_object = json.loads(content)
    919     except ValueError:
    920       raise ProductAttributesFileFormatError(
    921           'Wrong JSON format!')
    922     product_name = file_object.get(self.JSON_PRODUCT_NAME)
    923     attribute_string = file_object.get(self.JSON_PRODUCT_ATTRIBUTE)
    924     vboot_key_string = file_object.get(self.JSON_VBOOT_KEY)
    925     if not product_name or not attribute_string or not vboot_key_string:
    926       raise ProductAttributesFileFormatError(
    927           'Essential field missing!')
    928     try:
    929       attribute = base64.standard_b64decode(attribute_string)
    930       attribute_array = bytearray(attribute)
    931       if self.EXPECTED_ATTRIBUTE_LENGTH != len(attribute_array):
    932         raise ProductAttributesFileFormatError(
    933             'Incorrect permanent product attributes length')
    934 
    935       # We only need the last 16 byte for product ID
    936       # We store the hex representation of the product ID
    937       product_id = self._ByteToHex(attribute_array[-16:])
    938 
    939       vboot_key_array = bytearray(base64.standard_b64decode(vboot_key_string))
    940 
    941     except TypeError:
    942       raise ProductAttributesFileFormatError(
    943           'Incorrect Base64 encoding for permanent product attributes')
    944 
    945     self.product_info = ProductInfo(product_id, product_name, attribute_array,
    946                                     vboot_key_array)
    947 
    948   def _ByteToHex(self, byte_array):
    949     """Transform a byte array into a hex string."""
    950     return ''.join('{:02x}'.format(x) for x in byte_array)
    951 
    952   @staticmethod
    953   def CheckDevice(device):
    954     """Check if the device is a connected fastboot device.
    955 
    956     Args:
    957       device: The device to be checked.
    958     Raises:
    959       DeviceNotFoundException: When the device is not found
    960     """
    961     if device is None:
    962       raise DeviceNotFoundException()
    963 
    964 
    965 class AtfaDeviceManager(object):
    966   """The class to manager ATFA device related operations."""
    967 
    968   def __init__(self, atft_manager):
    969     """Initiate the atfa device manager using the at-factory-tool manager.
    970 
    971     Args:
    972       atft_manager: The at-factory-tool manager that
    973         includes this atfa device manager.
    974     """
    975     self.atft_manager = atft_manager
    976 
    977   def GetSerial(self):
    978     """Issue fastboot command to get serial number for the ATFA device.
    979 
    980     Raises:
    981       DeviceNotFoundException: When the device is not found.
    982     """
    983     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
    984     self.atft_manager.atfa_dev.Oem('serial')
    985 
    986   def SwitchStorage(self):
    987     """Switch the ATFA device to storage mode.
    988 
    989     Raises:
    990       DeviceNotFoundException: When the device is not found
    991     """
    992     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
    993     self.atft_manager.atfa_dev.Oem('storage')
    994 
    995   def ProcessKey(self):
    996     """Ask the ATFA device to process the stored key bundle.
    997 
    998     Raises:
    999       DeviceNotFoundException: When the device is not found
   1000     """
   1001     # Need to set time first so that certificates would validate.
   1002     self.SetTime()
   1003     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
   1004     self.atft_manager.atfa_dev.Oem('process-keybundle')
   1005 
   1006   def Reboot(self):
   1007     """Reboot the ATFA device.
   1008 
   1009     Raises:
   1010       DeviceNotFoundException: When the device is not found
   1011     """
   1012     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
   1013     self.atft_manager.atfa_dev.Oem('reboot')
   1014 
   1015   def Shutdown(self):
   1016     """Shutdown the ATFA device.
   1017 
   1018     Raises:
   1019       DeviceNotFoundException: When the device is not found
   1020     """
   1021     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
   1022     self.atft_manager.atfa_dev.Oem('shutdown')
   1023 
   1024   def CheckStatus(self):
   1025     """Update the number of available AT keys for the current product.
   1026 
   1027     Need to use GetKeysLeft() function to get the number of keys left. If some
   1028     error happens, keys_left would be set to -1 to prevent checking again.
   1029 
   1030     Raises:
   1031       FastbootFailure: If error happens with the fastboot oem command.
   1032     """
   1033 
   1034     if not self.atft_manager.product_info:
   1035       raise ProductNotSpecifiedException()
   1036 
   1037     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
   1038     # -1 means some error happens.
   1039     self.atft_manager.atfa_dev.keys_left = -1
   1040     out = self.atft_manager.atfa_dev.Oem(
   1041         'num-keys ' + self.atft_manager.product_info.product_id, True)
   1042     # Note: use splitlines instead of split('\n') to prevent '\r\n' problem on
   1043     # windows.
   1044     for line in out.splitlines():
   1045       if line.startswith('(bootloader) '):
   1046         try:
   1047           self.atft_manager.atfa_dev.keys_left = int(
   1048               line.replace('(bootloader) ', ''))
   1049           return
   1050         except ValueError:
   1051           raise FastbootFailure(
   1052               'ATFA device response has invalid format')
   1053 
   1054     raise FastbootFailure('ATFA device response has invalid format')
   1055 
   1056   def SetTime(self):
   1057     """Inject the host time into the ATFA device.
   1058 
   1059     Raises:
   1060       DeviceNotFoundException: When the device is not found
   1061     """
   1062     AtftManager.CheckDevice(self.atft_manager.atfa_dev)
   1063     time = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')
   1064     self.atft_manager.atfa_dev.Oem('set-date ' + time)
   1065