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""" 6This module provides utilities needed to provision and run test on Android 7devices. 8""" 9 10 11import logging 12import re 13 14import common 15from autotest_lib.client.common_lib import global_config 16 17 18CONFIG = global_config.global_config 19 20def 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 38class 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 113class 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 191class 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