xref: /aosp_15_r20/system/update_engine/scripts/cow_converter.py (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*5a923131SAndroid Build Coastguard Worker#
3*5a923131SAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project
4*5a923131SAndroid Build Coastguard Worker#
5*5a923131SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*5a923131SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*5a923131SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*5a923131SAndroid Build Coastguard Worker#
9*5a923131SAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*5a923131SAndroid Build Coastguard Worker#
11*5a923131SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*5a923131SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*5a923131SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*5a923131SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*5a923131SAndroid Build Coastguard Worker# limitations under the License.
16*5a923131SAndroid Build Coastguard Worker#
17*5a923131SAndroid Build Coastguard Worker
18*5a923131SAndroid Build Coastguard Worker"""Command-line tool for converting OTA payloads to VABC style COW images."""
19*5a923131SAndroid Build Coastguard Worker
20*5a923131SAndroid Build Coastguard Workerimport os
21*5a923131SAndroid Build Coastguard Workerimport sys
22*5a923131SAndroid Build Coastguard Workerimport tempfile
23*5a923131SAndroid Build Coastguard Workerimport zipfile
24*5a923131SAndroid Build Coastguard Workerimport subprocess
25*5a923131SAndroid Build Coastguard Worker
26*5a923131SAndroid Build Coastguard Worker
27*5a923131SAndroid Build Coastguard Workerdef IsSparseImage(filepath):
28*5a923131SAndroid Build Coastguard Worker  """Determine if an image is a sparse image
29*5a923131SAndroid Build Coastguard Worker  Args:
30*5a923131SAndroid Build Coastguard Worker    filepath: str, a path to an .img file
31*5a923131SAndroid Build Coastguard Worker
32*5a923131SAndroid Build Coastguard Worker  Returns:
33*5a923131SAndroid Build Coastguard Worker    return true iff the filepath is a sparse image.
34*5a923131SAndroid Build Coastguard Worker
35*5a923131SAndroid Build Coastguard Worker  """
36*5a923131SAndroid Build Coastguard Worker  with open(filepath, 'rb') as fp:
37*5a923131SAndroid Build Coastguard Worker    # Magic for android sparse image format
38*5a923131SAndroid Build Coastguard Worker    # https://source.android.com/devices/bootloader/images
39*5a923131SAndroid Build Coastguard Worker    return fp.read(4) == b'\x3A\xFF\x26\xED'
40*5a923131SAndroid Build Coastguard Worker
41*5a923131SAndroid Build Coastguard Worker
42*5a923131SAndroid Build Coastguard Workerdef ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir):
43*5a923131SAndroid Build Coastguard Worker  """Convert ota payload to COW IMAGE
44*5a923131SAndroid Build Coastguard Worker  Args:
45*5a923131SAndroid Build Coastguard Worker    ota_path: str, path to ota.zip
46*5a923131SAndroid Build Coastguard Worker    target_file_path: str, path to target_file.zip,
47*5a923131SAndroid Build Coastguard Worker      must be the target build for OTA.
48*5a923131SAndroid Build Coastguard Worker    tmp_dir: A temp dir as scratch space
49*5a923131SAndroid Build Coastguard Worker    output_dir: A directory where all converted COW images will be written.
50*5a923131SAndroid Build Coastguard Worker  """
51*5a923131SAndroid Build Coastguard Worker  with zipfile.ZipFile(ota_path) as ota_zip:
52*5a923131SAndroid Build Coastguard Worker    payload_path = ota_zip.extract("payload.bin", output_dir)
53*5a923131SAndroid Build Coastguard Worker  with zipfile.ZipFile(target_file_path) as zfp:
54*5a923131SAndroid Build Coastguard Worker    for fileinfo in zfp.infolist():
55*5a923131SAndroid Build Coastguard Worker      img_name = os.path.basename(fileinfo.filename)
56*5a923131SAndroid Build Coastguard Worker      if not fileinfo.filename.endswith(".img"):
57*5a923131SAndroid Build Coastguard Worker        continue
58*5a923131SAndroid Build Coastguard Worker      if fileinfo.filename.startswith("IMAGES/") or \
59*5a923131SAndroid Build Coastguard Worker              fileinfo.filename.startswith("RADIO/"):
60*5a923131SAndroid Build Coastguard Worker        img_path = zfp.extract(fileinfo, tmp_dir)
61*5a923131SAndroid Build Coastguard Worker        target_img_path = os.path.join(output_dir, img_name)
62*5a923131SAndroid Build Coastguard Worker        if IsSparseImage(img_path):
63*5a923131SAndroid Build Coastguard Worker          subprocess.check_call(["simg2img", img_path, target_img_path])
64*5a923131SAndroid Build Coastguard Worker        else:
65*5a923131SAndroid Build Coastguard Worker          os.rename(img_path, target_img_path)
66*5a923131SAndroid Build Coastguard Worker        print("Extracted", fileinfo.filename, "size:", fileinfo.file_size)
67*5a923131SAndroid Build Coastguard Worker
68*5a923131SAndroid Build Coastguard Worker  subprocess.call(["cow_converter", payload_path,
69*5a923131SAndroid Build Coastguard Worker                   output_dir])
70*5a923131SAndroid Build Coastguard Worker
71*5a923131SAndroid Build Coastguard Worker
72*5a923131SAndroid Build Coastguard Workerdef main():
73*5a923131SAndroid Build Coastguard Worker  if len(sys.argv) != 4:
74*5a923131SAndroid Build Coastguard Worker    print(
75*5a923131SAndroid Build Coastguard Worker        "Usage:", sys.argv[0], "<your_ota.zip> <target_file.zip> <output dir>")
76*5a923131SAndroid Build Coastguard Worker    return 1
77*5a923131SAndroid Build Coastguard Worker  ota_path = sys.argv[1]
78*5a923131SAndroid Build Coastguard Worker  target_file_path = sys.argv[2]
79*5a923131SAndroid Build Coastguard Worker  output_dir = sys.argv[3]
80*5a923131SAndroid Build Coastguard Worker  os.makedirs(output_dir, exist_ok=True)
81*5a923131SAndroid Build Coastguard Worker  with tempfile.TemporaryDirectory() as tmp_dir:
82*5a923131SAndroid Build Coastguard Worker    ConvertCOW(ota_path, target_file_path, tmp_dir, output_dir)
83*5a923131SAndroid Build Coastguard Worker  return 0
84*5a923131SAndroid Build Coastguard Worker
85*5a923131SAndroid Build Coastguard Worker
86*5a923131SAndroid Build Coastguard Workerif __name__ == '__main__':
87*5a923131SAndroid Build Coastguard Worker  sys.exit(main())
88