#!/usr/bin/env python3 # Copyright (C) 2020 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Generate payload.bin from a single image. """ import argparse import logging import os import re import shutil import sys from zipfile import ZipFile import common from ota_from_target_files import (Payload, PayloadSigner) logger = logging.getLogger(__name__) OPTIONS = common.OPTIONS def _ParseArgs(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--tools", metavar="PATH", type=str, nargs="*", help="A list of real paths of tools that this script depends on.") parser.add_argument("--key", type=str, help="Key to use to sign the package. If unspecified, script does not sign " "the package and payload_properties.txt is not generated.") parser.add_argument("--out", type=str, required=True, help="Required output directory to payload.bin and payload_properties.txt") parser.add_argument("input", metavar="NAME:IMAGE", nargs="+", help="Name of the image and path to the image, e.g. boot:path/to/boot.img") args = parser.parse_args() return args def _PrepareEnvironment(args): common.InitLogging() if not args.tools: return for path in args.tools: name = os.path.basename(path) # Use absolute path because GetBootImageTimestamp changes cwd when running some tools. common.SetHostToolLocation(name, os.path.abspath(path)) # brillo_update_payload is a shell script that depends on this environment variable. if name == "delta_generator": os.environ["GENERATOR"] = path def CreateOtaFromRawImages(args): _PrepareEnvironment(args) tf = common.MakeTempFile("target_files", ".zip") payload_additional_args = ["--is_partial_update", "true"] with ZipFile(tf, "w") as zip: names = [] for pair_str in args.input: pair = pair_str.split(":") assert len(pair) == 2, "Incorrect format: " + pair_str name, img_path = tuple(pair) zip.write(img_path, arcname=os.path.join("IMAGES", name + ".img")) names.append(name) if name == "boot": timestamp = common.GetBootImageTimestamp(img_path) assert timestamp is not None, "Cannot extract timestamp from boot image" payload_additional_args += ["--partition_timestamps", "boot:" + str(timestamp)] zip.writestr("META/ab_partitions.txt", "\n".join(names) + "\n") zip.writestr("META/dynamic_partitions_info.txt", """ virtual_ab=true super_partition_groups= """) payload = Payload() payload.Generate(tf, None, payload_additional_args) if args.key: OPTIONS.package_key = args.key OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) payload_signer = PayloadSigner() payload.Sign(payload_signer) shutil.copy(payload.payload_file, os.path.join(args.out, "payload.bin")) if payload.payload_properties: shutil.copy(payload.payload_properties, os.path.join(args.out, "payload_properties.txt")) if __name__ == "__main__": try: common.CloseInheritedPipes() args = _ParseArgs() CreateOtaFromRawImages(args) except common.ExternalError: logger.exception("\n ERROR:\n") sys.exit(1) finally: common.Cleanup()