• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17import importlib
18import os
19import stat
20
21from host_controller import common
22from host_controller.build import build_flasher
23from host_controller.command_processor import base_command_processor
24
25
26class 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(common._DEFAULT_FLASH_IMAGES) +
54            " 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 device booting.")
94        self.arg_parser.add_argument(
95            "--reboot", default="false", help="true to reboot the device(s).")
96        self.arg_parser.add_argument(
97            "--skip-vbmeta",
98            default=False,
99            type=bool,
100            help="true to skip flashing vbmeta.img if the device does not have "
101            "the vbmeta slot .")
102
103    # @Override
104    def Run(self, arg_line):
105        """Flash GSI or build images to a device connected with ADB."""
106        args = self.arg_parser.ParseLine(arg_line)
107
108        # path
109        if (self.console.tools_info is not None
110                and args.flasher_path in self.console.tools_info):
111            flasher_path = self.console.tools_info[args.flasher_path]
112        elif args.flasher_path:
113            flasher_path = args.flasher_path
114        else:
115            flasher_path = ""
116        if os.path.exists(flasher_path):
117            flasher_mode = os.stat(flasher_path).st_mode
118            os.chmod(flasher_path,
119                     flasher_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
120
121        # serial numbers
122        if args.serial:
123            flasher_serials = [args.serial]
124        elif self.console._serials:
125            flasher_serials = self.console._serials
126        else:
127            flasher_serials = [""]
128
129        # images
130        if args.image:
131            partition_image = {}
132            partition_image[args.image] = self.console.device_image_info[
133                args.image]
134        else:
135            if args.current:
136                partition_image = dict((partition,
137                                        self.console.device_image_info[image])
138                                       for partition, image in args.current)
139            else:
140                partition_image = dict(
141                    (image.rsplit(".img", 1)[0],
142                     self.console.device_image_info[image])
143                    for image in common._DEFAULT_FLASH_IMAGES
144                    if image in self.console.device_image_info)
145
146        # type
147        if args.flasher_type in ("fastboot", "custom"):
148            flasher_class = build_flasher.BuildFlasher
149        else:
150            class_path = args.flasher_type.rsplit(".", 1)
151            flasher_module = importlib.import_module(class_path[0])
152            flasher_class = getattr(flasher_module, class_path[1])
153            if not issubclass(flasher_class, build_flasher.BuildFlasher):
154                raise TypeError(
155                    "%s is not a subclass of BuildFlasher." % class_path[1])
156
157        flashers = [flasher_class(s, flasher_path) for s in flasher_serials]
158
159        # Can be parallelized as long as that's proven reliable.
160        for flasher in flashers:
161            ret_flash = True
162            if args.flasher_type == "fastboot":
163                if args.image is not None:
164                    ret_flash = flasher.FlashImage(partition_image, True
165                                                   if args.reboot == "true"
166                                                   else False)
167                elif args.current is not None:
168                    ret_flash = flasher.Flash(partition_image,
169                                              args.skip_vbmeta)
170                else:
171                    if args.gsi is None and args.build_dir is None:
172                        self.arg_parser.error("Nothing requested: "
173                                              "specify --gsi or --build_dir")
174                        return False
175                    if args.build_dir is not None:
176                        ret_flash = flasher.Flashall(args.build_dir)
177                    if args.gsi is not None:
178                        ret_flash = flasher.FlashGSI(
179                            args.gsi,
180                            args.vbmeta,
181                            skip_vbmeta=args.skip_vbmeta)
182            elif args.flasher_type == "custom":
183                if flasher_path is not None:
184                    if args.repackage is not None:
185                        flasher.RepackageArtifacts(
186                            self.console.device_image_info, args.repackage)
187                    ret_flash = flasher.FlashUsingCustomBinary(
188                        self.console.device_image_info, args.reboot_mode,
189                        args.flasher_args, 300)
190                else:
191                    self.arg_parser.error(
192                        "Please specify the path to custom flash tool.")
193                    return False
194            else:
195                ret_flash = flasher.Flash(partition_image,
196                                          self.console.tools_info,
197                                          *args.flasher_args)
198            if ret_flash == False:
199                return False
200
201        if args.wait_for_boot == "true":
202            for flasher in flashers:
203                ret_wait = flasher.WaitForDevice()
204                if ret_wait == False:
205                    self.console.device_status[
206                        flasher.device.serial] = common._DEVICE_STATUS_DICT[
207                            "error"]
208                    self.console.vti_endpoint_client.SetJobStatusFromLeasedTo(
209                        "bootup-err")
210                    return False
211