Home | History | Annotate | Download | only in common_lib
      1 # Copyright 2016 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 
      5 """
      6 This module provides utilities needed to provision and run test on Android
      7 devices.
      8 """
      9 
     10 
     11 import logging
     12 import re
     13 
     14 import common
     15 from autotest_lib.client.common_lib import global_config
     16 
     17 
     18 CONFIG = global_config.global_config
     19 
     20 def get_config_value_regex(section, regex):
     21     """Get config values from global config based on regex of the key.
     22 
     23     @param section: Section of the config, e.g., CLIENT.
     24     @param regex: Regular expression of the key pattern.
     25 
     26     @return: A dictionary of all config values matching the regex. Value is
     27              assumed to be comma separated, and is converted to a list.
     28     """
     29     configs = CONFIG.get_config_value_regex(section, regex)
     30     result = {}
     31     for key, value in configs.items():
     32         match = re.match(regex, key)
     33         result[match.group(1)] = [v.strip() for v in value.split(',')
     34                                   if v.strip()]
     35     return result
     36 
     37 
     38 class AndroidAliases(object):
     39     """Wrapper class for getting alias names for an android device.
     40 
     41     On android it is only possible to get a devices product name
     42     (eg. marlin, sailfish). However a product may have several aliases
     43     that it is called by such as the name of its board, or a public name,
     44     etc. This wrapper allows for mapping the product name to different
     45     aliases.
     46 
     47     Terms:
     48         product: The name a device reports itself as.
     49         board: The name of the hardware board in a device.
     50         alias: Some name a device is called, this includes both product and
     51                board.
     52     """
     53 
     54     # regex pattern for CLIENT/android_aliases_[product]. For example,
     55     # global config can have following config in CLIENT section to indicate that
     56     # android product name `zzz` has following aliases.
     57     # ['my_board', 'xyz'].
     58     # android_board_aliases_zzz: my_board,xyz
     59     ALIASES_PATTERN = 'android_aliases_(.*)'
     60 
     61     # A dict of product:aliases for product aliases, can be defined in global
     62     # config CLIENT/android_aliases_[product]
     63     aliases_map = get_config_value_regex('CLIENT',
     64                                          ALIASES_PATTERN)
     65 
     66     # regex pattern for CLIENT/android_board_name[product]. For example,
     67     # global config can have following config in CLIENT section to indicate that
     68     # android product `zzz` has following board name.
     69     # xyz.
     70     # android_board_name_zzz: xyz
     71     BOARD_NAME_PATTERN = 'android_board_name_(.*)'
     72 
     73 
     74     # A dict of product:board for product board names, can be defined in global
     75     # config CLIENT/android_board_name_[product]
     76     board_name_map = get_config_value_regex('CLIENT', BOARD_NAME_PATTERN)
     77 
     78     @classmethod
     79     def get_product_aliases(cls, product):
     80         """Get all aliases for a android product name.
     81 
     82         Androids can have multiple aliases for a single product. These aliases
     83         may be what the device is called in different configs. For example
     84         bat has a board name of bat_land. Therefore the product name bat
     85         can be referenced as either bat or batland.
     86 
     87         @param product: The name of the product that is reported for a device.
     88         @returns: All aliases for that product (including the product name).
     89         """
     90         aliases = set(cls.aliases_map.get(product, []))
     91         aliases.add(cls.get_board_name(product))
     92         aliases.add(product)
     93 
     94         return aliases
     95 
     96     @classmethod
     97     def get_board_name(cls, product):
     98         """Get the board name of a product.
     99 
    100         The board name of an android device is what the hardware is named.
    101         In many cases this is the same name as the reported product name,
    102         however some devices have boards that differ from the product name.
    103 
    104         @param product: The name of the product.
    105         @returns: The board name of the given product.
    106         """
    107         boards = cls.board_name_map.get(product, None)
    108         if boards:
    109             return boards[0]
    110         return product
    111 
    112 
    113 class AndroidImageFiles(object):
    114     """A wrapper class for constants and methods related to image files.
    115     """
    116 
    117     BOOTLOADER = 'bootloader.img'
    118     RADIO = 'radio.img'
    119     BOOT = 'boot.img'
    120     SYSTEM = 'system.img'
    121     VENDOR = 'vendor.img'
    122     VBMETA = 'vbmeta.img'
    123     DTBO = 'dtbo.img'
    124 
    125     # Image files not inside the image zip file. These files should be
    126     # downloaded directly from devserver.
    127     DEFAULT_STANDALONE_IMAGES = [BOOTLOADER, RADIO]
    128 
    129     # Default image files that are packaged in a zip file, e.g.,
    130     # shamu-img-123456.zip
    131     DEFAULT_ZIPPED_IMAGES = [BOOT, SYSTEM, VENDOR, VBMETA, DTBO]
    132 
    133     # Default image files to be flashed to an Android device.
    134     DEFAULT_IMAGES = DEFAULT_STANDALONE_IMAGES + DEFAULT_ZIPPED_IMAGES
    135 
    136     # regex pattern for CLIENT/android_standalone_images_[board]. For example,
    137     # global config can have following config in CLIENT section to indicate that
    138     # android board `xyz` has following standalone images.
    139     # ['bootloader_image', 'radio_image'].
    140     # android_standalone_xyz: bootloader.img,radio.img
    141     STANDALONE_IMAGES_PATTERN = 'android_standalone_images_(.*)'
    142 
    143     # A dict of board:images for standalone images, can be defined in global
    144     # config CLIENT/android_standalone_images_[board]
    145     standalone_images_map = get_config_value_regex('CLIENT',
    146                                                    STANDALONE_IMAGES_PATTERN)
    147 
    148     # regex pattern for CLIENT/android_standalone_images_[board]. For example,
    149     # global config can have following config in CLIENT section to indicate that
    150     # android board `xyz` has following standalone images.
    151     # ['bootloader_image', 'radio_image'].
    152     # android_zipped_xyz: bootloader.img,radio.img
    153     ZIPPED_IMAGES_PATTERN = 'android_zipped_images_(.*)'
    154 
    155     # A dict of board:images for zipped images, can be defined in global
    156     # config CLIENT/android_zipped_images_[board]
    157     zipped_images_map = get_config_value_regex('CLIENT', ZIPPED_IMAGES_PATTERN)
    158 
    159     @classmethod
    160     def get_standalone_images(cls, board):
    161         """Get a list of standalone image files for given board.
    162 
    163         @param board: Name of the board.
    164 
    165         @return: A list of standalone image files.
    166         """
    167         if board in cls.standalone_images_map:
    168             logging.debug('Found override of standalone image files for board '
    169                           '%s: %s', board, cls.standalone_images_map[board])
    170             return cls.standalone_images_map[board]
    171         else:
    172             return cls.DEFAULT_STANDALONE_IMAGES
    173 
    174 
    175     @classmethod
    176     def get_zipped_images(cls, board):
    177         """Get a list of image files from zip_images artifact for given board.
    178 
    179         @param board: Name of the board.
    180 
    181         @return: A list of image files from `zip_images`.
    182         """
    183         if board in cls.zipped_images_map:
    184             logging.debug('Found override of zip image files for board '
    185                           '%s: %s', board, cls.zipped_images_map[board])
    186             return cls.zipped_images_map[board]
    187         else:
    188             return cls.DEFAULT_ZIPPED_IMAGES
    189 
    190 
    191 class AndroidArtifacts(object):
    192     """A wrapper class for constants and methods related to artifacts.
    193     """
    194 
    195     BOOTLOADER_IMAGE = 'bootloader_image'
    196     DTB = 'dtb'
    197     RADIO_IMAGE = 'radio_image'
    198     TARGET_FILES = 'target_files'
    199     VENDOR_PARTITIONS = 'vendor_partitions'
    200     ZIP_IMAGE = 'zip_images'
    201 
    202     # (os, board) = 'artifacts'
    203     DEFAULT_ARTIFACTS_MAP = {
    204         ('android', 'default'): [BOOTLOADER_IMAGE, RADIO_IMAGE, ZIP_IMAGE],
    205         ('brillo', 'default'):  [ZIP_IMAGE, VENDOR_PARTITIONS],
    206         ('emulated_brillo', 'default'): [TARGET_FILES, DTB],
    207     }
    208 
    209     # Default artifacts for Android provision
    210     DEFAULT_ARTIFACTS_TO_BE_STAGED_FOR_IMAGE = (
    211             ','.join([BOOTLOADER_IMAGE, RADIO_IMAGE, ZIP_IMAGE]))
    212 
    213     # regex pattern for CLIENT/android_artifacts_[board]. For example, global
    214     # config can have following config in CLIENT section to indicate that
    215     # android board `xyz` needs to stage artifacts
    216     # ['bootloader_image', 'radio_image'] for provision.
    217     # android_artifacts_xyz: bootloader_image,radio_image
    218     ARTIFACTS_LIST_PATTERN = 'android_artifacts_(.*)'
    219 
    220     # A dict of board:artifacts, can be defined in global config
    221     # CLIENT/android_artifacts_[board]
    222     artifacts_map = get_config_value_regex('CLIENT', ARTIFACTS_LIST_PATTERN)
    223 
    224     @classmethod
    225     def get_artifacts_for_reimage(cls, board, os='android'):
    226         """Get artifacts need to be staged for reimage for given board.
    227 
    228         @param board: Name of the board.
    229 
    230         @return: A string of artifacts to be staged.
    231         """
    232         logging.debug('artifacts for %s %s', os, board)
    233         if board in cls.artifacts_map:
    234             logging.debug('Found override of artifacts for board %s: %s', board,
    235                           cls.artifacts_map[board])
    236             artifacts = cls.artifacts_map[board]
    237         elif (os, board) in cls.DEFAULT_ARTIFACTS_MAP:
    238             artifacts = cls.DEFAULT_ARTIFACTS_MAP[(os, board)]
    239         else:
    240             artifacts = cls.DEFAULT_ARTIFACTS_MAP[(os, 'default')]
    241         logging.debug('found %s', ','.join(artifacts))
    242         return ','.join(artifacts)
    243