1#!/usr/bin/env python3
2
3# Copyright (C) 2020 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""
18Generate payload.bin from a single image.
19"""
20
21import argparse
22import logging
23import os
24import re
25import shutil
26import sys
27from zipfile import ZipFile
28
29import common
30from ota_from_target_files import (Payload, PayloadSigner)
31
32logger = logging.getLogger(__name__)
33OPTIONS = common.OPTIONS
34
35
36def _ParseArgs():
37  parser = argparse.ArgumentParser(description=__doc__)
38  parser.add_argument("--tools", metavar="PATH", type=str, nargs="*",
39                      help="A list of real paths of tools that this script depends on.")
40  parser.add_argument("--key", type=str,
41                      help="Key to use to sign the package. If unspecified, script does not sign "
42                           "the package and payload_properties.txt is not generated.")
43  parser.add_argument("--out", type=str, required=True,
44                      help="Required output directory to payload.bin and payload_properties.txt")
45  parser.add_argument("input", metavar="NAME:IMAGE", nargs="+",
46                      help="Name of the image and path to the image, e.g. boot:path/to/boot.img")
47  args = parser.parse_args()
48
49  return args
50
51
52def _PrepareEnvironment(args):
53  common.InitLogging()
54  if not args.tools:
55    return
56  for path in args.tools:
57    name = os.path.basename(path)
58    # Use absolute path because GetBootImageTimestamp changes cwd when running some tools.
59    common.SetHostToolLocation(name, os.path.abspath(path))
60    # brillo_update_payload is a shell script that depends on this environment variable.
61    if name == "delta_generator":
62      os.environ["GENERATOR"] = path
63
64
65def CreateOtaFromRawImages(args):
66  _PrepareEnvironment(args)
67
68  tf = common.MakeTempFile("target_files", ".zip")
69  payload_additional_args = ["--is_partial_update", "true"]
70  with ZipFile(tf, "w") as zip:
71    names = []
72    for pair_str in args.input:
73      pair = pair_str.split(":")
74      assert len(pair) == 2, "Incorrect format: " + pair_str
75      name, img_path = tuple(pair)
76      zip.write(img_path, arcname=os.path.join("IMAGES", name + ".img"))
77      names.append(name)
78      if name == "boot":
79        timestamp = common.GetBootImageTimestamp(img_path)
80        assert timestamp is not None, "Cannot extract timestamp from boot image"
81        payload_additional_args += ["--partition_timestamps",
82                                    "boot:" + str(timestamp)]
83
84    zip.writestr("META/ab_partitions.txt", "\n".join(names) + "\n")
85    zip.writestr("META/dynamic_partitions_info.txt", """
86virtual_ab=true
87super_partition_groups=
88    """)
89
90  payload = Payload()
91  payload.Generate(tf, None, payload_additional_args)
92
93  if args.key:
94    OPTIONS.package_key = args.key
95    OPTIONS.key_passwords = common.GetKeyPasswords([OPTIONS.package_key])
96    payload_signer = PayloadSigner()
97    payload.Sign(payload_signer)
98
99  shutil.copy(payload.payload_file, os.path.join(args.out, "payload.bin"))
100  if payload.payload_properties:
101    shutil.copy(payload.payload_properties, os.path.join(args.out, "payload_properties.txt"))
102
103
104if __name__ == "__main__":
105  try:
106    common.CloseInheritedPipes()
107    args = _ParseArgs()
108    CreateOtaFromRawImages(args)
109  except common.ExternalError:
110    logger.exception("\n   ERROR:\n")
111    sys.exit(1)
112  finally:
113    common.Cleanup()
114