Home | History | Annotate | Download | only in command_processor
      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