Kelvin Zhang | c612f20 | 2021-02-26 14:22:10 -0500 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (C) 2021 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 | |
| 18 | """Command-line tool for converting OTA payloads to VABC style COW images.""" |
| 19 | |
| 20 | import os |
| 21 | import sys |
| 22 | import tempfile |
| 23 | import zipfile |
| 24 | import subprocess |
| 25 | |
| 26 | |
| 27 | def IsSparseImage(filepath): |
| 28 | """Determine if an image is a sparse image |
| 29 | Args: |
| 30 | filepath: str, a path to an .img file |
| 31 | |
| 32 | Returns: |
| 33 | return true iff the filepath is a sparse image. |
| 34 | |
| 35 | """ |
| 36 | with open(filepath, 'rb') as fp: |
| 37 | # Magic for android sparse image format |
| 38 | # https://source.android.com/devices/bootloader/images |
| 39 | return fp.read(4) == b'\x3A\xFF\x26\xED' |
| 40 | |
| 41 | |
| 42 | def ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir): |
| 43 | """Convert ota payload to COW IMAGE |
| 44 | Args: |
| 45 | ota_path: str, path to ota.zip |
| 46 | target_file_path: str, path to target_file.zip, |
| 47 | must be the target build for OTA. |
| 48 | tmp_dir: A temp dir as scratch space |
| 49 | output_dir: A directory where all converted COW images will be written. |
| 50 | """ |
| 51 | with zipfile.ZipFile(ota_path) as ota_zip: |
| 52 | payload_path = ota_zip.extract("payload.bin", output_dir) |
| 53 | with zipfile.ZipFile(target_file_path) as zfp: |
| 54 | for fileinfo in zfp.infolist(): |
| 55 | img_name = os.path.basename(fileinfo.filename) |
| 56 | if not fileinfo.filename.endswith(".img"): |
| 57 | continue |
| 58 | if fileinfo.filename.startswith("IMAGES/") or \ |
| 59 | fileinfo.filename.startswith("RADIO/"): |
| 60 | img_path = zfp.extract(fileinfo, tmp_dir) |
| 61 | target_img_path = os.path.join(output_dir, img_name) |
| 62 | if IsSparseImage(img_path): |
| 63 | subprocess.check_call(["simg2img", img_path, target_img_path]) |
| 64 | else: |
| 65 | os.rename(img_path, target_img_path) |
| 66 | print("Extracted", fileinfo.filename, "size:", fileinfo.file_size) |
| 67 | |
| 68 | subprocess.call(["cow_converter", payload_path, |
| 69 | output_dir]) |
| 70 | |
| 71 | |
| 72 | def main(): |
| 73 | if len(sys.argv) != 4: |
| 74 | print( |
| 75 | "Usage:", sys.argv[0], "<your_ota.zip> <target_file.zip> <output dir>") |
| 76 | return 1 |
| 77 | ota_path = sys.argv[1] |
| 78 | target_file_path = sys.argv[2] |
| 79 | output_dir = sys.argv[3] |
| 80 | os.makedirs(output_dir, exist_ok=True) |
| 81 | with tempfile.TemporaryDirectory() as tmp_dir: |
| 82 | ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir) |
| 83 | return 0 |
| 84 | |
| 85 | |
| 86 | if __name__ == '__main__': |
| 87 | sys.exit(main()) |