Add a tool to generate OTA from images
During build, we will need to generate an OTA for boot partition using a
16K boot image. Typically, OTA is generated from target_files.zip . To
avoid relying on target_files.zip as a dependency for 16K OTA, add a
tool to generate OTA directly from a raw image.
Test: th, ota_from_raw_img --partition_name boot --output ota.zip $OUT/boot_16k.img
Bug: 293313353
Change-Id: I2076332faf2a8dc573450597efd481e285a49545
diff --git a/tools/releasetools/ota_from_raw_img.py b/tools/releasetools/ota_from_raw_img.py
new file mode 100644
index 0000000..ac4f9fb
--- /dev/null
+++ b/tools/releasetools/ota_from_raw_img.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2008 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.
+
+"""
+Given a series of .img files, produces an OTA package that installs thoese images
+"""
+
+import sys
+import os
+import argparse
+import subprocess
+import tempfile
+import logging
+import zipfile
+
+import common
+from payload_signer import PayloadSigner
+from ota_utils import PayloadGenerator
+from ota_signing_utils import AddSigningArgumentParse
+
+
+logger = logging.getLogger(__name__)
+
+
+def ResolveBinaryPath(filename, search_path):
+ if not search_path:
+ return filename
+ if not os.path.exists(search_path):
+ return filename
+ path = os.path.join(search_path, "bin", filename)
+ if os.path.exists(path):
+ return path
+ path = os.path.join(search_path, filename)
+ if os.path.exists(path):
+ return path
+ return path
+
+
+def main(argv):
+ parser = argparse.ArgumentParser(
+ prog=argv[0], description="Given a series of .img files, produces a full OTA package that installs thoese images")
+ parser.add_argument("images", nargs="+", type=str,
+ help="List of images to generate OTA")
+ parser.add_argument("--partition_names", nargs='+', type=str,
+ help="Partition names to install the images, default to basename of the image(no file name extension)")
+ parser.add_argument('--output', type=str,
+ help='Paths to output merged ota', required=True)
+ parser.add_argument("-v", action="store_true",
+ help="Enable verbose logging", dest="verbose")
+ AddSigningArgumentParse(parser)
+
+ args = parser.parse_args(argv[1:])
+ if args.verbose:
+ logger.setLevel(logging.INFO)
+ logger.info(args)
+ if not args.partition_names:
+ args.partition_names = [os.path.os.path.splitext(os.path.basename(path))[
+ 0] for path in args.images]
+ with tempfile.NamedTemporaryFile() as unsigned_payload:
+ cmd = [ResolveBinaryPath("delta_generator", args.search_path)]
+ cmd.append("--partition_names=" + ",".join(args.partition_names))
+ cmd.append("--new_partitions=" + ",".join(args.images))
+ cmd.append("--out_file=" + unsigned_payload.name)
+ logger.info("Running %s", cmd)
+
+ subprocess.run(cmd)
+ generator = PayloadGenerator()
+ generator.payload_file = unsigned_payload.name
+ logger.info("Payload size: %d", os.path.getsize(generator.payload_file))
+
+ # Get signing keys
+ key_passwords = common.GetKeyPasswords([args.package_key])
+
+ if args.package_key:
+ logger.info("Signing payload...")
+ # TODO: remove OPTIONS when no longer used as fallback in payload_signer
+ common.OPTIONS.payload_signer_args = None
+ common.OPTIONS.payload_signer_maximum_signature_size = None
+ signer = PayloadSigner(args.package_key, args.private_key_suffix,
+ key_passwords[args.package_key],
+ payload_signer=args.payload_signer,
+ payload_signer_args=args.payload_signer_args,
+ payload_signer_maximum_signature_size=args.payload_signer_maximum_signature_size)
+ generator.payload_file = unsigned_payload.name
+ generator.Sign(signer)
+
+ logger.info("Payload size: %d", os.path.getsize(generator.payload_file))
+
+ logger.info("Writing to %s", args.output)
+ with zipfile.ZipFile(args.output, "w") as zfp:
+ generator.WriteToZip(zfp)
+
+
+if __name__ == "__main__":
+ logging.basicConfig()
+ main(sys.argv)