Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 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) |
Dan Shi | 749b64d | 2016-10-26 11:17:13 -0700 | [diff] [blame] | 33 | result[match.group(1)] = [v.strip() for v in value.split(',') |
| 34 | if v.strip()] |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 35 | return result |
| 36 | |
| 37 | |
Benny Peake | e8838cf | 2017-02-10 14:51:02 -0800 | [diff] [blame] | 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 | |
Benny Peake | e8838cf | 2017-02-10 14:51:02 -0800 | [diff] [blame] | 54 | # regex pattern for CLIENT/android_board_name[product]. For example, |
| 55 | # global config can have following config in CLIENT section to indicate that |
| 56 | # android product `zzz` has following board name. |
| 57 | # xyz. |
| 58 | # android_board_name_zzz: xyz |
| 59 | BOARD_NAME_PATTERN = 'android_board_name_(.*)' |
| 60 | |
| 61 | |
| 62 | # A dict of product:board for product board names, can be defined in global |
| 63 | # config CLIENT/android_board_name_[product] |
| 64 | board_name_map = get_config_value_regex('CLIENT', BOARD_NAME_PATTERN) |
| 65 | |
| 66 | @classmethod |
Benny Peake | e8838cf | 2017-02-10 14:51:02 -0800 | [diff] [blame] | 67 | def get_board_name(cls, product): |
| 68 | """Get the board name of a product. |
| 69 | |
| 70 | The board name of an android device is what the hardware is named. |
| 71 | In many cases this is the same name as the reported product name, |
| 72 | however some devices have boards that differ from the product name. |
| 73 | |
| 74 | @param product: The name of the product. |
| 75 | @returns: The board name of the given product. |
| 76 | """ |
| 77 | boards = cls.board_name_map.get(product, None) |
| 78 | if boards: |
| 79 | return boards[0] |
| 80 | return product |
| 81 | |
| 82 | |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 83 | class AndroidArtifacts(object): |
| 84 | """A wrapper class for constants and methods related to artifacts. |
| 85 | """ |
| 86 | |
| 87 | BOOTLOADER_IMAGE = 'bootloader_image' |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 88 | DTB = 'dtb' |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 89 | RADIO_IMAGE = 'radio_image' |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 90 | TARGET_FILES = 'target_files' |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 91 | VENDOR_PARTITIONS = 'vendor_partitions' |
| 92 | ZIP_IMAGE = 'zip_images' |
| 93 | |
| 94 | # (os, board) = 'artifacts' |
| 95 | DEFAULT_ARTIFACTS_MAP = { |
Benny Peake | bdbea87 | 2016-12-07 13:18:09 -0800 | [diff] [blame] | 96 | ('android', 'default'): [BOOTLOADER_IMAGE, RADIO_IMAGE, ZIP_IMAGE], |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 97 | ('brillo', 'default'): [ZIP_IMAGE, VENDOR_PARTITIONS], |
| 98 | ('emulated_brillo', 'default'): [TARGET_FILES, DTB], |
| 99 | } |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 100 | |
| 101 | # Default artifacts for Android provision |
| 102 | DEFAULT_ARTIFACTS_TO_BE_STAGED_FOR_IMAGE = ( |
Benny Peake | bdbea87 | 2016-12-07 13:18:09 -0800 | [diff] [blame] | 103 | ','.join([BOOTLOADER_IMAGE, RADIO_IMAGE, ZIP_IMAGE])) |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 104 | |
| 105 | # regex pattern for CLIENT/android_artifacts_[board]. For example, global |
| 106 | # config can have following config in CLIENT section to indicate that |
| 107 | # android board `xyz` needs to stage artifacts |
| 108 | # ['bootloader_image', 'radio_image'] for provision. |
| 109 | # android_artifacts_xyz: bootloader_image,radio_image |
| 110 | ARTIFACTS_LIST_PATTERN = 'android_artifacts_(.*)' |
| 111 | |
| 112 | # A dict of board:artifacts, can be defined in global config |
| 113 | # CLIENT/android_artifacts_[board] |
| 114 | artifacts_map = get_config_value_regex('CLIENT', ARTIFACTS_LIST_PATTERN) |
| 115 | |
| 116 | @classmethod |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 117 | def get_artifacts_for_reimage(cls, board, os='android'): |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 118 | """Get artifacts need to be staged for reimage for given board. |
| 119 | |
| 120 | @param board: Name of the board. |
| 121 | |
| 122 | @return: A string of artifacts to be staged. |
| 123 | """ |
Benny Peake | bcbe2b6 | 2016-12-19 16:21:33 -0800 | [diff] [blame] | 124 | logging.debug('artifacts for %s %s', os, board) |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 125 | if board in cls.artifacts_map: |
| 126 | logging.debug('Found override of artifacts for board %s: %s', board, |
| 127 | cls.artifacts_map[board]) |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 128 | artifacts = cls.artifacts_map[board] |
| 129 | elif (os, board) in cls.DEFAULT_ARTIFACTS_MAP: |
| 130 | artifacts = cls.DEFAULT_ARTIFACTS_MAP[(os, board)] |
Dan Shi | 49d451f | 2016-04-19 09:25:01 -0700 | [diff] [blame] | 131 | else: |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 132 | artifacts = cls.DEFAULT_ARTIFACTS_MAP[(os, 'default')] |
Benny Peake | bcbe2b6 | 2016-12-19 16:21:33 -0800 | [diff] [blame] | 133 | logging.debug('found %s', ','.join(artifacts)) |
Justin Giorgi | dd05a94 | 2016-07-05 20:53:12 -0700 | [diff] [blame] | 134 | return ','.join(artifacts) |