xref: /aosp_15_r20/build/make/tools/releasetools/merge/merge_builds.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2019 The Android Open Source Project
4*9e94795aSAndroid Build Coastguard Worker#
5*9e94795aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6*9e94795aSAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of
7*9e94795aSAndroid Build Coastguard Worker# the License at
8*9e94795aSAndroid Build Coastguard Worker#
9*9e94795aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*9e94795aSAndroid Build Coastguard Worker#
11*9e94795aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*9e94795aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13*9e94795aSAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14*9e94795aSAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under
15*9e94795aSAndroid Build Coastguard Worker# the License.
16*9e94795aSAndroid Build Coastguard Worker#
17*9e94795aSAndroid Build Coastguard Worker"""Merges two non-dist partial builds together.
18*9e94795aSAndroid Build Coastguard Worker
19*9e94795aSAndroid Build Coastguard WorkerGiven two partial builds, a framework build and a vendor build, merge the builds
20*9e94795aSAndroid Build Coastguard Workertogether so that the images can be flashed using 'fastboot flashall'.
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard WorkerTo support both DAP and non-DAP vendor builds with a single framework partial
23*9e94795aSAndroid Build Coastguard Workerbuild, the framework partial build should always be built with DAP enabled. The
24*9e94795aSAndroid Build Coastguard Workervendor partial build determines whether the merged result supports DAP.
25*9e94795aSAndroid Build Coastguard Worker
26*9e94795aSAndroid Build Coastguard WorkerThis script does not require builds to be built with 'make dist'.
27*9e94795aSAndroid Build Coastguard WorkerThis script regenerates super_empty.img and vbmeta.img if necessary. Other
28*9e94795aSAndroid Build Coastguard Workerimages are assumed to not require regeneration.
29*9e94795aSAndroid Build Coastguard Worker
30*9e94795aSAndroid Build Coastguard WorkerUsage: merge_builds.py [args]
31*9e94795aSAndroid Build Coastguard Worker
32*9e94795aSAndroid Build Coastguard Worker  --framework_images comma_separated_image_list
33*9e94795aSAndroid Build Coastguard Worker      Comma-separated list of image names that should come from the framework
34*9e94795aSAndroid Build Coastguard Worker      build.
35*9e94795aSAndroid Build Coastguard Worker
36*9e94795aSAndroid Build Coastguard Worker  --product_out_framework product_out_framework_path
37*9e94795aSAndroid Build Coastguard Worker      Path to out/target/product/<framework build>.
38*9e94795aSAndroid Build Coastguard Worker
39*9e94795aSAndroid Build Coastguard Worker  --product_out_vendor product_out_vendor_path
40*9e94795aSAndroid Build Coastguard Worker      Path to out/target/product/<vendor build>.
41*9e94795aSAndroid Build Coastguard Worker
42*9e94795aSAndroid Build Coastguard Worker  --build_vbmeta
43*9e94795aSAndroid Build Coastguard Worker      If provided, vbmeta.img will be regenerated in out/target/product/<vendor
44*9e94795aSAndroid Build Coastguard Worker      build>.
45*9e94795aSAndroid Build Coastguard Worker
46*9e94795aSAndroid Build Coastguard Worker  --framework_misc_info_keys
47*9e94795aSAndroid Build Coastguard Worker      The optional path to a newline-separated config file containing keys to
48*9e94795aSAndroid Build Coastguard Worker      obtain from the framework instance of misc_info.txt, used for creating
49*9e94795aSAndroid Build Coastguard Worker      vbmeta.img. The remaining keys come from the vendor instance.
50*9e94795aSAndroid Build Coastguard Worker
51*9e94795aSAndroid Build Coastguard Worker  --avb_resolve_rollback_index_location_conflict
52*9e94795aSAndroid Build Coastguard Worker      If provided, resolve the conflict AVB rollback index location when
53*9e94795aSAndroid Build Coastguard Worker      necessary.
54*9e94795aSAndroid Build Coastguard Worker"""
55*9e94795aSAndroid Build Coastguard Workerfrom __future__ import print_function
56*9e94795aSAndroid Build Coastguard Worker
57*9e94795aSAndroid Build Coastguard Workerimport logging
58*9e94795aSAndroid Build Coastguard Workerimport os
59*9e94795aSAndroid Build Coastguard Workerimport sys
60*9e94795aSAndroid Build Coastguard Worker
61*9e94795aSAndroid Build Coastguard Workerimport build_super_image
62*9e94795aSAndroid Build Coastguard Workerimport common
63*9e94795aSAndroid Build Coastguard Worker
64*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
65*9e94795aSAndroid Build Coastguard Worker
66*9e94795aSAndroid Build Coastguard WorkerOPTIONS = common.OPTIONS
67*9e94795aSAndroid Build Coastguard WorkerOPTIONS.framework_images = ("system",)
68*9e94795aSAndroid Build Coastguard WorkerOPTIONS.product_out_framework = None
69*9e94795aSAndroid Build Coastguard WorkerOPTIONS.product_out_vendor = None
70*9e94795aSAndroid Build Coastguard WorkerOPTIONS.build_vbmeta = False
71*9e94795aSAndroid Build Coastguard WorkerOPTIONS.framework_misc_info_keys = None
72*9e94795aSAndroid Build Coastguard WorkerOPTIONS.avb_resolve_rollback_index_location_conflict = False
73*9e94795aSAndroid Build Coastguard Worker
74*9e94795aSAndroid Build Coastguard Worker
75*9e94795aSAndroid Build Coastguard Workerdef CreateImageSymlinks():
76*9e94795aSAndroid Build Coastguard Worker  for image in OPTIONS.framework_images:
77*9e94795aSAndroid Build Coastguard Worker    image_path = os.path.join(OPTIONS.product_out_framework, "%s.img" % image)
78*9e94795aSAndroid Build Coastguard Worker    symlink_path = os.path.join(OPTIONS.product_out_vendor, "%s.img" % image)
79*9e94795aSAndroid Build Coastguard Worker    if os.path.exists(symlink_path):
80*9e94795aSAndroid Build Coastguard Worker      if os.path.islink(symlink_path):
81*9e94795aSAndroid Build Coastguard Worker        os.remove(symlink_path)
82*9e94795aSAndroid Build Coastguard Worker      else:
83*9e94795aSAndroid Build Coastguard Worker        raise ValueError("Attempting to overwrite built image: %s" %
84*9e94795aSAndroid Build Coastguard Worker                         symlink_path)
85*9e94795aSAndroid Build Coastguard Worker    os.symlink(image_path, symlink_path)
86*9e94795aSAndroid Build Coastguard Worker
87*9e94795aSAndroid Build Coastguard Worker
88*9e94795aSAndroid Build Coastguard Workerdef BuildSuperEmpty():
89*9e94795aSAndroid Build Coastguard Worker  framework_dict = common.LoadDictionaryFromFile(
90*9e94795aSAndroid Build Coastguard Worker      os.path.join(OPTIONS.product_out_framework, "misc_info.txt"))
91*9e94795aSAndroid Build Coastguard Worker  vendor_dict = common.LoadDictionaryFromFile(
92*9e94795aSAndroid Build Coastguard Worker      os.path.join(OPTIONS.product_out_vendor, "misc_info.txt"))
93*9e94795aSAndroid Build Coastguard Worker  # Regenerate super_empty.img if both partial builds enable DAP. If only the
94*9e94795aSAndroid Build Coastguard Worker  # the vendor build enables DAP, the vendor build's existing super_empty.img
95*9e94795aSAndroid Build Coastguard Worker  # will be reused. If only the framework build should enable DAP, super_empty
96*9e94795aSAndroid Build Coastguard Worker  # should be included in the --framework_images flag to copy the existing
97*9e94795aSAndroid Build Coastguard Worker  # super_empty.img from the framework build.
98*9e94795aSAndroid Build Coastguard Worker  if (framework_dict.get("use_dynamic_partitions") == "true") and (
99*9e94795aSAndroid Build Coastguard Worker      vendor_dict.get("use_dynamic_partitions") == "true"):
100*9e94795aSAndroid Build Coastguard Worker    logger.info("Building super_empty.img.")
101*9e94795aSAndroid Build Coastguard Worker    merged_dict = dict(vendor_dict)
102*9e94795aSAndroid Build Coastguard Worker    merged_dict.update(
103*9e94795aSAndroid Build Coastguard Worker        common.MergeDynamicPartitionInfoDicts(
104*9e94795aSAndroid Build Coastguard Worker            framework_dict=framework_dict, vendor_dict=vendor_dict))
105*9e94795aSAndroid Build Coastguard Worker    output_super_empty_path = os.path.join(OPTIONS.product_out_vendor,
106*9e94795aSAndroid Build Coastguard Worker                                           "super_empty.img")
107*9e94795aSAndroid Build Coastguard Worker    build_super_image.BuildSuperImage(merged_dict, output_super_empty_path)
108*9e94795aSAndroid Build Coastguard Worker
109*9e94795aSAndroid Build Coastguard Worker
110*9e94795aSAndroid Build Coastguard Workerdef BuildVBMeta():
111*9e94795aSAndroid Build Coastguard Worker  logger.info("Building vbmeta.img.")
112*9e94795aSAndroid Build Coastguard Worker
113*9e94795aSAndroid Build Coastguard Worker  framework_dict = common.LoadDictionaryFromFile(
114*9e94795aSAndroid Build Coastguard Worker      os.path.join(OPTIONS.product_out_framework, "misc_info.txt"))
115*9e94795aSAndroid Build Coastguard Worker  vendor_dict = common.LoadDictionaryFromFile(
116*9e94795aSAndroid Build Coastguard Worker      os.path.join(OPTIONS.product_out_vendor, "misc_info.txt"))
117*9e94795aSAndroid Build Coastguard Worker  merged_dict = dict(vendor_dict)
118*9e94795aSAndroid Build Coastguard Worker  if OPTIONS.framework_misc_info_keys:
119*9e94795aSAndroid Build Coastguard Worker    for key in common.LoadListFromFile(OPTIONS.framework_misc_info_keys):
120*9e94795aSAndroid Build Coastguard Worker      merged_dict[key] = framework_dict[key]
121*9e94795aSAndroid Build Coastguard Worker
122*9e94795aSAndroid Build Coastguard Worker  # Build vbmeta.img using partitions in product_out_vendor.
123*9e94795aSAndroid Build Coastguard Worker  partitions = {}
124*9e94795aSAndroid Build Coastguard Worker  for partition in common.AVB_PARTITIONS:
125*9e94795aSAndroid Build Coastguard Worker    partition_path = os.path.join(OPTIONS.product_out_vendor,
126*9e94795aSAndroid Build Coastguard Worker                                  "%s.img" % partition)
127*9e94795aSAndroid Build Coastguard Worker    if os.path.exists(partition_path):
128*9e94795aSAndroid Build Coastguard Worker      partitions[partition] = partition_path
129*9e94795aSAndroid Build Coastguard Worker
130*9e94795aSAndroid Build Coastguard Worker  # vbmeta_partitions includes the partitions that should be included into
131*9e94795aSAndroid Build Coastguard Worker  # top-level vbmeta.img, which are the ones that are not included in any
132*9e94795aSAndroid Build Coastguard Worker  # chained VBMeta image plus the chained VBMeta images themselves.
133*9e94795aSAndroid Build Coastguard Worker  vbmeta_partitions = common.AVB_PARTITIONS[:]
134*9e94795aSAndroid Build Coastguard Worker  for partition in common.AVB_VBMETA_PARTITIONS:
135*9e94795aSAndroid Build Coastguard Worker    chained_partitions = merged_dict.get("avb_%s" % partition, "").strip()
136*9e94795aSAndroid Build Coastguard Worker    if chained_partitions:
137*9e94795aSAndroid Build Coastguard Worker      partitions[partition] = os.path.join(OPTIONS.product_out_vendor,
138*9e94795aSAndroid Build Coastguard Worker                                           "%s.img" % partition)
139*9e94795aSAndroid Build Coastguard Worker      vbmeta_partitions = [
140*9e94795aSAndroid Build Coastguard Worker          item for item in vbmeta_partitions
141*9e94795aSAndroid Build Coastguard Worker          if item not in chained_partitions.split()
142*9e94795aSAndroid Build Coastguard Worker      ]
143*9e94795aSAndroid Build Coastguard Worker      vbmeta_partitions.append(partition)
144*9e94795aSAndroid Build Coastguard Worker
145*9e94795aSAndroid Build Coastguard Worker  output_vbmeta_path = os.path.join(OPTIONS.product_out_vendor, "vbmeta.img")
146*9e94795aSAndroid Build Coastguard Worker  OPTIONS.info_dict = merged_dict
147*9e94795aSAndroid Build Coastguard Worker  common.BuildVBMeta(output_vbmeta_path, partitions, "vbmeta",
148*9e94795aSAndroid Build Coastguard Worker                     vbmeta_partitions,
149*9e94795aSAndroid Build Coastguard Worker                     OPTIONS.avb_resolve_rollback_index_location_conflict)
150*9e94795aSAndroid Build Coastguard Worker
151*9e94795aSAndroid Build Coastguard Worker
152*9e94795aSAndroid Build Coastguard Workerdef MergeBuilds():
153*9e94795aSAndroid Build Coastguard Worker  CreateImageSymlinks()
154*9e94795aSAndroid Build Coastguard Worker  BuildSuperEmpty()
155*9e94795aSAndroid Build Coastguard Worker  if OPTIONS.build_vbmeta:
156*9e94795aSAndroid Build Coastguard Worker    BuildVBMeta()
157*9e94795aSAndroid Build Coastguard Worker
158*9e94795aSAndroid Build Coastguard Worker
159*9e94795aSAndroid Build Coastguard Workerdef main():
160*9e94795aSAndroid Build Coastguard Worker  common.InitLogging()
161*9e94795aSAndroid Build Coastguard Worker
162*9e94795aSAndroid Build Coastguard Worker  def option_handler(o, a):
163*9e94795aSAndroid Build Coastguard Worker    if o == "--framework_images":
164*9e94795aSAndroid Build Coastguard Worker      OPTIONS.framework_images = [i.strip() for i in a.split(",")]
165*9e94795aSAndroid Build Coastguard Worker    elif o == "--product_out_framework":
166*9e94795aSAndroid Build Coastguard Worker      OPTIONS.product_out_framework = a
167*9e94795aSAndroid Build Coastguard Worker    elif o == "--product_out_vendor":
168*9e94795aSAndroid Build Coastguard Worker      OPTIONS.product_out_vendor = a
169*9e94795aSAndroid Build Coastguard Worker    elif o == "--build_vbmeta":
170*9e94795aSAndroid Build Coastguard Worker      OPTIONS.build_vbmeta = True
171*9e94795aSAndroid Build Coastguard Worker    elif o == "--framework_misc_info_keys":
172*9e94795aSAndroid Build Coastguard Worker      OPTIONS.framework_misc_info_keys = a
173*9e94795aSAndroid Build Coastguard Worker    elif o == "--avb_resolve_rollback_index_location_conflict":
174*9e94795aSAndroid Build Coastguard Worker      OPTIONS.avb_resolve_rollback_index_location_conflict = True
175*9e94795aSAndroid Build Coastguard Worker    else:
176*9e94795aSAndroid Build Coastguard Worker      return False
177*9e94795aSAndroid Build Coastguard Worker    return True
178*9e94795aSAndroid Build Coastguard Worker
179*9e94795aSAndroid Build Coastguard Worker  args = common.ParseOptions(
180*9e94795aSAndroid Build Coastguard Worker      sys.argv[1:],
181*9e94795aSAndroid Build Coastguard Worker      __doc__,
182*9e94795aSAndroid Build Coastguard Worker      extra_long_opts=[
183*9e94795aSAndroid Build Coastguard Worker          "framework_images=",
184*9e94795aSAndroid Build Coastguard Worker          "product_out_framework=",
185*9e94795aSAndroid Build Coastguard Worker          "product_out_vendor=",
186*9e94795aSAndroid Build Coastguard Worker          "build_vbmeta",
187*9e94795aSAndroid Build Coastguard Worker          "framework_misc_info_keys=",
188*9e94795aSAndroid Build Coastguard Worker          "avb_resolve_rollback_index_location_conflict"
189*9e94795aSAndroid Build Coastguard Worker      ],
190*9e94795aSAndroid Build Coastguard Worker      extra_option_handler=option_handler)
191*9e94795aSAndroid Build Coastguard Worker
192*9e94795aSAndroid Build Coastguard Worker  if (args or OPTIONS.product_out_framework is None or
193*9e94795aSAndroid Build Coastguard Worker      OPTIONS.product_out_vendor is None):
194*9e94795aSAndroid Build Coastguard Worker    common.Usage(__doc__)
195*9e94795aSAndroid Build Coastguard Worker    sys.exit(1)
196*9e94795aSAndroid Build Coastguard Worker
197*9e94795aSAndroid Build Coastguard Worker  MergeBuilds()
198*9e94795aSAndroid Build Coastguard Worker
199*9e94795aSAndroid Build Coastguard Worker
200*9e94795aSAndroid Build Coastguard Workerif __name__ == "__main__":
201*9e94795aSAndroid Build Coastguard Worker  main()
202