1 # 2 # Copyright (C) 2018 The Android Open Source Project 3 # 4 # Licensed under the Apache License, Version 2.0 (the 'License'); 5 # you may not use this file except in compliance with the License. 6 # You may obtain a copy of the License at 7 # 8 # http://www.apache.org/licenses/LICENSE-2.0 9 # 10 # Unless required by applicable law or agreed to in writing, software 11 # distributed under the License is distributed on an 'AS IS' BASIS, 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 # See the License for the specific language governing permissions and 14 # limitations under the License. 15 # 16 17 import importlib 18 import os 19 import stat 20 21 from host_controller import common 22 from host_controller.build import build_flasher 23 from host_controller.command_processor import base_command_processor 24 25 26 class CommandFlash(base_command_processor.BaseCommandProcessor): 27 """Command processor for flash command. 28 29 Attributes: 30 arg_parser: ConsoleArgumentParser object, argument parser. 31 console: cmd.Cmd console object. 32 command: string, command name which this processor will handle. 33 command_detail: string, detailed explanation for the command. 34 """ 35 36 command = "flash" 37 command_detail = "Flash images to a device." 38 39 # @Override 40 def SetUp(self): 41 """Initializes the parser for flash command.""" 42 self.arg_parser.add_argument( 43 "--image", 44 help=("The file name of an image to flash." 45 " Used to flash a single image.")) 46 self.arg_parser.add_argument( 47 "--current", 48 metavar="PARTITION_IMAGE", 49 nargs="*", 50 type=lambda x: x.split("="), 51 help="The partitions and images to be flashed. The format is " 52 "<partition>=<image>. If PARTITION_IMAGE list is empty, " 53 "currently fetched " + ", ".join( 54 common._DEFAULT_FLASH_IMAGES) + " will be flashed.") 55 self.arg_parser.add_argument( 56 "--serial", default="", help="Serial number for device.") 57 self.arg_parser.add_argument( 58 "--build_dir", 59 help="Directory containing build images to be flashed.") 60 self.arg_parser.add_argument( 61 "--gsi", help="Path to generic system image") 62 self.arg_parser.add_argument("--vbmeta", help="Path to vbmeta image") 63 self.arg_parser.add_argument( 64 "--flasher_type", 65 default="fastboot", 66 help="Flasher type. Valid arguments are \"fastboot\", \"custom\", " 67 "and full module name followed by class name. The class must " 68 "inherit build_flasher.BuildFlasher, and implement " 69 "__init__(serial, flasher_path) and " 70 "Flash(device_images, additional_files, *flasher_args).") 71 self.arg_parser.add_argument( 72 "--flasher_path", default=None, help="Path to a flasher binary") 73 self.arg_parser.add_argument( 74 "flasher_args", 75 metavar="ARGUMENTS", 76 nargs="*", 77 help="The arguments passed to the flasher binary. If any argument " 78 "starts with \"-\", place all of them after \"--\" at end of " 79 "line.") 80 self.arg_parser.add_argument( 81 "--reboot_mode", 82 default="bootloader", 83 choices=("bootloader", "download"), 84 help="Reboot device to bootloader/download mode") 85 self.arg_parser.add_argument( 86 "--repackage", 87 default="tar.md5", 88 choices=("tar.md5"), 89 help="Repackage artifacts into given format before flashing.") 90 self.arg_parser.add_argument( 91 "--wait-for-boot", 92 default="true", 93 help="false to not wait for devie booting.") 94 self.arg_parser.add_argument( 95 "--reboot", default="false", help="true to reboot the device(s).") 96 97 # @Override 98 def Run(self, arg_line): 99 """Flash GSI or build images to a device connected with ADB.""" 100 args = self.arg_parser.ParseLine(arg_line) 101 102 # path 103 if (self.console.tools_info is not None 104 and args.flasher_path in self.console.tools_info): 105 flasher_path = self.console.tools_info[args.flasher_path] 106 elif args.flasher_path: 107 flasher_path = args.flasher_path 108 else: 109 flasher_path = "" 110 if os.path.exists(flasher_path): 111 flasher_mode = os.stat(flasher_path).st_mode 112 os.chmod(flasher_path, 113 flasher_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 114 115 # serial numbers 116 if args.serial: 117 flasher_serials = [args.serial] 118 elif self.console._serials: 119 flasher_serials = self.console._serials 120 else: 121 flasher_serials = [""] 122 123 # images 124 if args.image: 125 partition_image = {} 126 partition_image[args.image] = self.console.device_image_info[ 127 args.image] 128 else: 129 if args.current: 130 partition_image = dict((partition, 131 self.console.device_image_info[image]) 132 for partition, image in args.current) 133 else: 134 partition_image = dict( 135 (image.rsplit(".img", 1)[0], 136 self.console.device_image_info[image]) 137 for image in common._DEFAULT_FLASH_IMAGES 138 if image in self.console.device_image_info) 139 140 # type 141 if args.flasher_type in ("fastboot", "custom"): 142 flasher_class = build_flasher.BuildFlasher 143 else: 144 class_path = args.flasher_type.rsplit(".", 1) 145 flasher_module = importlib.import_module(class_path[0]) 146 flasher_class = getattr(flasher_module, class_path[1]) 147 if not issubclass(flasher_class, build_flasher.BuildFlasher): 148 raise TypeError( 149 "%s is not a subclass of BuildFlasher." % class_path[1]) 150 151 flashers = [flasher_class(s, flasher_path) for s in flasher_serials] 152 153 # Can be parallelized as long as that's proven reliable. 154 for flasher in flashers: 155 ret_flash = True 156 if args.flasher_type == "fastboot": 157 if args.image is not None: 158 ret_flash = flasher.FlashImage(partition_image, True 159 if args.reboot == "true" 160 else False) 161 elif args.current is not None: 162 ret_flash = flasher.Flash(partition_image) 163 else: 164 if args.gsi is None and args.build_dir is None: 165 self.arg_parser.error("Nothing requested: " 166 "specify --gsi or --build_dir") 167 return False 168 if args.build_dir is not None: 169 ret_flash = flasher.Flashall(args.build_dir) 170 if args.gsi is not None: 171 ret_flash = flasher.FlashGSI(args.gsi, args.vbmeta) 172 elif args.flasher_type == "custom": 173 if flasher_path is not None: 174 if args.repackage is not None: 175 flasher.RepackageArtifacts( 176 self.console.device_image_info, args.repackage) 177 ret_flash = flasher.FlashUsingCustomBinary( 178 self.console.device_image_info, args.reboot_mode, 179 args.flasher_args, 300) 180 else: 181 self.arg_parser.error( 182 "Please specify the path to custom flash tool.") 183 return False 184 else: 185 ret_flash = flasher.Flash(partition_image, 186 self.console.tools_info, 187 *args.flasher_args) 188 if ret_flash == False: 189 return False 190 191 if args.wait_for_boot == "true": 192 for flasher in flashers: 193 ret_wait = flasher.WaitForDevice() 194 if ret_wait == False: 195 return False 196