| 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()) |