xref: /aosp_15_r20/build/make/tools/releasetools/merge/merge_meta.py (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
1*9e94795aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*9e94795aSAndroid Build Coastguard Worker#
3*9e94795aSAndroid Build Coastguard Worker# Copyright (C) 2022 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"""Functions for merging META/* files from partial builds.
18*9e94795aSAndroid Build Coastguard Worker
19*9e94795aSAndroid Build Coastguard WorkerExpects items in OPTIONS prepared by merge_target_files.py.
20*9e94795aSAndroid Build Coastguard Worker"""
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard Workerimport logging
23*9e94795aSAndroid Build Coastguard Workerimport os
24*9e94795aSAndroid Build Coastguard Workerimport re
25*9e94795aSAndroid Build Coastguard Workerimport shutil
26*9e94795aSAndroid Build Coastguard Worker
27*9e94795aSAndroid Build Coastguard Workerimport build_image
28*9e94795aSAndroid Build Coastguard Workerimport common
29*9e94795aSAndroid Build Coastguard Workerimport merge_utils
30*9e94795aSAndroid Build Coastguard Workerimport sparse_img
31*9e94795aSAndroid Build Coastguard Workerimport verity_utils
32*9e94795aSAndroid Build Coastguard Workerfrom ota_utils import ParseUpdateEngineConfig
33*9e94795aSAndroid Build Coastguard Worker
34*9e94795aSAndroid Build Coastguard Workerfrom common import ExternalError
35*9e94795aSAndroid Build Coastguard Worker
36*9e94795aSAndroid Build Coastguard Workerlogger = logging.getLogger(__name__)
37*9e94795aSAndroid Build Coastguard Worker
38*9e94795aSAndroid Build Coastguard WorkerOPTIONS = common.OPTIONS
39*9e94795aSAndroid Build Coastguard Worker
40*9e94795aSAndroid Build Coastguard Worker# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
41*9e94795aSAndroid Build Coastguard Worker# the file. We use these partition tags to filter the entries in those files
42*9e94795aSAndroid Build Coastguard Worker# from the two different target files packages to produce a merged apexkeys.txt
43*9e94795aSAndroid Build Coastguard Worker# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
44*9e94795aSAndroid Build Coastguard Worker# like this: 'partition="product"'. We use the group syntax grab the value of
45*9e94795aSAndroid Build Coastguard Worker# the tag. We use non-greedy matching in case there are other fields on the
46*9e94795aSAndroid Build Coastguard Worker# same line.
47*9e94795aSAndroid Build Coastguard Worker
48*9e94795aSAndroid Build Coastguard WorkerPARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
49*9e94795aSAndroid Build Coastguard Worker
50*9e94795aSAndroid Build Coastguard Worker# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
51*9e94795aSAndroid Build Coastguard Worker# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
52*9e94795aSAndroid Build Coastguard Worker
53*9e94795aSAndroid Build Coastguard WorkerMODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
54*9e94795aSAndroid Build Coastguard Worker
55*9e94795aSAndroid Build Coastguard Worker
56*9e94795aSAndroid Build Coastguard Workerdef MergeUpdateEngineConfig(framework_meta_dir, vendor_meta_dir,
57*9e94795aSAndroid Build Coastguard Worker                            merged_meta_dir):
58*9e94795aSAndroid Build Coastguard Worker  """Merges META/update_engine_config.txt.
59*9e94795aSAndroid Build Coastguard Worker
60*9e94795aSAndroid Build Coastguard Worker  The output is the configuration for maximum compatibility.
61*9e94795aSAndroid Build Coastguard Worker  """
62*9e94795aSAndroid Build Coastguard Worker  _CONFIG_NAME = 'update_engine_config.txt'
63*9e94795aSAndroid Build Coastguard Worker  framework_config_path = os.path.join(framework_meta_dir, _CONFIG_NAME)
64*9e94795aSAndroid Build Coastguard Worker  vendor_config_path = os.path.join(vendor_meta_dir, _CONFIG_NAME)
65*9e94795aSAndroid Build Coastguard Worker  merged_config_path = os.path.join(merged_meta_dir, _CONFIG_NAME)
66*9e94795aSAndroid Build Coastguard Worker
67*9e94795aSAndroid Build Coastguard Worker  if os.path.exists(framework_config_path):
68*9e94795aSAndroid Build Coastguard Worker    framework_config = ParseUpdateEngineConfig(framework_config_path)
69*9e94795aSAndroid Build Coastguard Worker    vendor_config = ParseUpdateEngineConfig(vendor_config_path)
70*9e94795aSAndroid Build Coastguard Worker    # Copy older config to merged target files for maximum compatibility
71*9e94795aSAndroid Build Coastguard Worker    # update_engine in system partition is from system side, but
72*9e94795aSAndroid Build Coastguard Worker    # update_engine_sideload in recovery is from vendor side.
73*9e94795aSAndroid Build Coastguard Worker    if framework_config < vendor_config:
74*9e94795aSAndroid Build Coastguard Worker      shutil.copy(framework_config_path, merged_config_path)
75*9e94795aSAndroid Build Coastguard Worker    else:
76*9e94795aSAndroid Build Coastguard Worker      shutil.copy(vendor_config_path, merged_config_path)
77*9e94795aSAndroid Build Coastguard Worker  else:
78*9e94795aSAndroid Build Coastguard Worker    if not OPTIONS.allow_partial_ab:
79*9e94795aSAndroid Build Coastguard Worker      raise FileNotFoundError(framework_config_path)
80*9e94795aSAndroid Build Coastguard Worker    shutil.copy(vendor_config_path, merged_config_path)
81*9e94795aSAndroid Build Coastguard Worker
82*9e94795aSAndroid Build Coastguard Worker
83*9e94795aSAndroid Build Coastguard Workerdef MergeMetaFiles(temp_dir, merged_dir, framework_partitions):
84*9e94795aSAndroid Build Coastguard Worker  """Merges various files in META/*."""
85*9e94795aSAndroid Build Coastguard Worker
86*9e94795aSAndroid Build Coastguard Worker  framework_meta_dir = os.path.join(temp_dir, 'framework_meta', 'META')
87*9e94795aSAndroid Build Coastguard Worker  merge_utils.CollectTargetFiles(
88*9e94795aSAndroid Build Coastguard Worker      input_zipfile_or_dir=OPTIONS.framework_target_files,
89*9e94795aSAndroid Build Coastguard Worker      output_dir=os.path.dirname(framework_meta_dir),
90*9e94795aSAndroid Build Coastguard Worker      item_list=('META/*',))
91*9e94795aSAndroid Build Coastguard Worker
92*9e94795aSAndroid Build Coastguard Worker  vendor_meta_dir = os.path.join(temp_dir, 'vendor_meta', 'META')
93*9e94795aSAndroid Build Coastguard Worker  merge_utils.CollectTargetFiles(
94*9e94795aSAndroid Build Coastguard Worker      input_zipfile_or_dir=OPTIONS.vendor_target_files,
95*9e94795aSAndroid Build Coastguard Worker      output_dir=os.path.dirname(vendor_meta_dir),
96*9e94795aSAndroid Build Coastguard Worker      item_list=('META/*',))
97*9e94795aSAndroid Build Coastguard Worker
98*9e94795aSAndroid Build Coastguard Worker  merged_meta_dir = os.path.join(merged_dir, 'META')
99*9e94795aSAndroid Build Coastguard Worker
100*9e94795aSAndroid Build Coastguard Worker  # Merge META/misc_info.txt into OPTIONS.merged_misc_info,
101*9e94795aSAndroid Build Coastguard Worker  # but do not write it yet. The following functions may further
102*9e94795aSAndroid Build Coastguard Worker  # modify this dict.
103*9e94795aSAndroid Build Coastguard Worker  OPTIONS.merged_misc_info = MergeMiscInfo(
104*9e94795aSAndroid Build Coastguard Worker      framework_meta_dir=framework_meta_dir,
105*9e94795aSAndroid Build Coastguard Worker      vendor_meta_dir=vendor_meta_dir,
106*9e94795aSAndroid Build Coastguard Worker      merged_meta_dir=merged_meta_dir)
107*9e94795aSAndroid Build Coastguard Worker
108*9e94795aSAndroid Build Coastguard Worker  CopyNamedFileContexts(
109*9e94795aSAndroid Build Coastguard Worker      framework_meta_dir=framework_meta_dir,
110*9e94795aSAndroid Build Coastguard Worker      vendor_meta_dir=vendor_meta_dir,
111*9e94795aSAndroid Build Coastguard Worker      merged_meta_dir=merged_meta_dir)
112*9e94795aSAndroid Build Coastguard Worker
113*9e94795aSAndroid Build Coastguard Worker  if OPTIONS.merged_misc_info.get('use_dynamic_partitions') == 'true':
114*9e94795aSAndroid Build Coastguard Worker    MergeDynamicPartitionsInfo(
115*9e94795aSAndroid Build Coastguard Worker        framework_meta_dir=framework_meta_dir,
116*9e94795aSAndroid Build Coastguard Worker        vendor_meta_dir=vendor_meta_dir,
117*9e94795aSAndroid Build Coastguard Worker        merged_meta_dir=merged_meta_dir)
118*9e94795aSAndroid Build Coastguard Worker
119*9e94795aSAndroid Build Coastguard Worker  if OPTIONS.merged_misc_info.get('ab_update') == 'true':
120*9e94795aSAndroid Build Coastguard Worker    MergeAbPartitions(
121*9e94795aSAndroid Build Coastguard Worker        framework_meta_dir=framework_meta_dir,
122*9e94795aSAndroid Build Coastguard Worker        vendor_meta_dir=vendor_meta_dir,
123*9e94795aSAndroid Build Coastguard Worker        merged_meta_dir=merged_meta_dir,
124*9e94795aSAndroid Build Coastguard Worker        framework_partitions=framework_partitions)
125*9e94795aSAndroid Build Coastguard Worker    UpdateCareMapImageSizeProps(images_dir=os.path.join(merged_dir, 'IMAGES'))
126*9e94795aSAndroid Build Coastguard Worker
127*9e94795aSAndroid Build Coastguard Worker  for file_name in ('apkcerts.txt', 'apexkeys.txt'):
128*9e94795aSAndroid Build Coastguard Worker    MergePackageKeys(
129*9e94795aSAndroid Build Coastguard Worker        framework_meta_dir=framework_meta_dir,
130*9e94795aSAndroid Build Coastguard Worker        vendor_meta_dir=vendor_meta_dir,
131*9e94795aSAndroid Build Coastguard Worker        merged_meta_dir=merged_meta_dir,
132*9e94795aSAndroid Build Coastguard Worker        file_name=file_name)
133*9e94795aSAndroid Build Coastguard Worker
134*9e94795aSAndroid Build Coastguard Worker  if OPTIONS.merged_misc_info.get('ab_update') == 'true':
135*9e94795aSAndroid Build Coastguard Worker    MergeUpdateEngineConfig(
136*9e94795aSAndroid Build Coastguard Worker        framework_meta_dir, vendor_meta_dir, merged_meta_dir)
137*9e94795aSAndroid Build Coastguard Worker
138*9e94795aSAndroid Build Coastguard Worker  # Write the now-finalized OPTIONS.merged_misc_info.
139*9e94795aSAndroid Build Coastguard Worker  merge_utils.WriteSortedData(
140*9e94795aSAndroid Build Coastguard Worker      data=OPTIONS.merged_misc_info,
141*9e94795aSAndroid Build Coastguard Worker      path=os.path.join(merged_meta_dir, 'misc_info.txt'))
142*9e94795aSAndroid Build Coastguard Worker
143*9e94795aSAndroid Build Coastguard Worker
144*9e94795aSAndroid Build Coastguard Workerdef MergeAbPartitions(framework_meta_dir, vendor_meta_dir, merged_meta_dir,
145*9e94795aSAndroid Build Coastguard Worker                      framework_partitions):
146*9e94795aSAndroid Build Coastguard Worker  """Merges META/ab_partitions.txt.
147*9e94795aSAndroid Build Coastguard Worker
148*9e94795aSAndroid Build Coastguard Worker  The output contains the union of the partition names.
149*9e94795aSAndroid Build Coastguard Worker  """
150*9e94795aSAndroid Build Coastguard Worker  framework_ab_partitions = []
151*9e94795aSAndroid Build Coastguard Worker  framework_ab_config = os.path.join(framework_meta_dir, 'ab_partitions.txt')
152*9e94795aSAndroid Build Coastguard Worker  if os.path.exists(framework_ab_config):
153*9e94795aSAndroid Build Coastguard Worker    with open(framework_ab_config) as f:
154*9e94795aSAndroid Build Coastguard Worker      # Filter out some partitions here to support the case that the
155*9e94795aSAndroid Build Coastguard Worker      # ab_partitions.txt of framework-target-files has non-framework
156*9e94795aSAndroid Build Coastguard Worker      # partitions. This case happens when we use a complete merged target
157*9e94795aSAndroid Build Coastguard Worker      # files package as the framework-target-files.
158*9e94795aSAndroid Build Coastguard Worker      framework_ab_partitions.extend([
159*9e94795aSAndroid Build Coastguard Worker          partition
160*9e94795aSAndroid Build Coastguard Worker          for partition in f.read().splitlines()
161*9e94795aSAndroid Build Coastguard Worker          if partition in framework_partitions
162*9e94795aSAndroid Build Coastguard Worker      ])
163*9e94795aSAndroid Build Coastguard Worker  else:
164*9e94795aSAndroid Build Coastguard Worker    if not OPTIONS.allow_partial_ab:
165*9e94795aSAndroid Build Coastguard Worker      raise FileNotFoundError(framework_ab_config)
166*9e94795aSAndroid Build Coastguard Worker    logger.info('Use partial AB because framework ab_partitions.txt does not '
167*9e94795aSAndroid Build Coastguard Worker                'exist.')
168*9e94795aSAndroid Build Coastguard Worker
169*9e94795aSAndroid Build Coastguard Worker  with open(os.path.join(vendor_meta_dir, 'ab_partitions.txt')) as f:
170*9e94795aSAndroid Build Coastguard Worker    vendor_ab_partitions = f.read().splitlines()
171*9e94795aSAndroid Build Coastguard Worker
172*9e94795aSAndroid Build Coastguard Worker  merge_utils.WriteSortedData(
173*9e94795aSAndroid Build Coastguard Worker      data=set(framework_ab_partitions + vendor_ab_partitions),
174*9e94795aSAndroid Build Coastguard Worker      path=os.path.join(merged_meta_dir, 'ab_partitions.txt'))
175*9e94795aSAndroid Build Coastguard Worker
176*9e94795aSAndroid Build Coastguard Worker
177*9e94795aSAndroid Build Coastguard Workerdef MergeMiscInfo(framework_meta_dir, vendor_meta_dir, merged_meta_dir):
178*9e94795aSAndroid Build Coastguard Worker  """Merges META/misc_info.txt.
179*9e94795aSAndroid Build Coastguard Worker
180*9e94795aSAndroid Build Coastguard Worker  The output contains a combination of key=value pairs from both inputs.
181*9e94795aSAndroid Build Coastguard Worker  Most pairs are taken from the vendor input, while some are taken from
182*9e94795aSAndroid Build Coastguard Worker  the framework input.
183*9e94795aSAndroid Build Coastguard Worker  """
184*9e94795aSAndroid Build Coastguard Worker
185*9e94795aSAndroid Build Coastguard Worker  OPTIONS.framework_misc_info = common.LoadDictionaryFromFile(
186*9e94795aSAndroid Build Coastguard Worker      os.path.join(framework_meta_dir, 'misc_info.txt'))
187*9e94795aSAndroid Build Coastguard Worker  OPTIONS.vendor_misc_info = common.LoadDictionaryFromFile(
188*9e94795aSAndroid Build Coastguard Worker      os.path.join(vendor_meta_dir, 'misc_info.txt'))
189*9e94795aSAndroid Build Coastguard Worker
190*9e94795aSAndroid Build Coastguard Worker  # Merged misc info is a combination of vendor misc info plus certain values
191*9e94795aSAndroid Build Coastguard Worker  # from the framework misc info.
192*9e94795aSAndroid Build Coastguard Worker
193*9e94795aSAndroid Build Coastguard Worker  merged_dict = OPTIONS.vendor_misc_info
194*9e94795aSAndroid Build Coastguard Worker  for key in OPTIONS.framework_misc_info_keys:
195*9e94795aSAndroid Build Coastguard Worker    if key in OPTIONS.framework_misc_info:
196*9e94795aSAndroid Build Coastguard Worker      merged_dict[key] = OPTIONS.framework_misc_info[key]
197*9e94795aSAndroid Build Coastguard Worker
198*9e94795aSAndroid Build Coastguard Worker  # If AVB is enabled then ensure that we build vbmeta.img.
199*9e94795aSAndroid Build Coastguard Worker  # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
200*9e94795aSAndroid Build Coastguard Worker  # skip building an incomplete vbmeta.img.
201*9e94795aSAndroid Build Coastguard Worker  if merged_dict.get('avb_enable') == 'true':
202*9e94795aSAndroid Build Coastguard Worker    merged_dict['avb_building_vbmeta_image'] = 'true'
203*9e94795aSAndroid Build Coastguard Worker
204*9e94795aSAndroid Build Coastguard Worker  return merged_dict
205*9e94795aSAndroid Build Coastguard Worker
206*9e94795aSAndroid Build Coastguard Worker
207*9e94795aSAndroid Build Coastguard Workerdef MergeDynamicPartitionsInfo(framework_meta_dir, vendor_meta_dir,
208*9e94795aSAndroid Build Coastguard Worker                               merged_meta_dir):
209*9e94795aSAndroid Build Coastguard Worker  """Merge META/dynamic_partitions_info.txt."""
210*9e94795aSAndroid Build Coastguard Worker  framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
211*9e94795aSAndroid Build Coastguard Worker      os.path.join(framework_meta_dir, 'dynamic_partitions_info.txt'))
212*9e94795aSAndroid Build Coastguard Worker  vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
213*9e94795aSAndroid Build Coastguard Worker      os.path.join(vendor_meta_dir, 'dynamic_partitions_info.txt'))
214*9e94795aSAndroid Build Coastguard Worker
215*9e94795aSAndroid Build Coastguard Worker  merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
216*9e94795aSAndroid Build Coastguard Worker      framework_dict=framework_dynamic_partitions_dict,
217*9e94795aSAndroid Build Coastguard Worker      vendor_dict=vendor_dynamic_partitions_dict)
218*9e94795aSAndroid Build Coastguard Worker
219*9e94795aSAndroid Build Coastguard Worker  merge_utils.WriteSortedData(
220*9e94795aSAndroid Build Coastguard Worker      data=merged_dynamic_partitions_dict,
221*9e94795aSAndroid Build Coastguard Worker      path=os.path.join(merged_meta_dir, 'dynamic_partitions_info.txt'))
222*9e94795aSAndroid Build Coastguard Worker
223*9e94795aSAndroid Build Coastguard Worker  # Merge misc info keys used for Dynamic Partitions.
224*9e94795aSAndroid Build Coastguard Worker  OPTIONS.merged_misc_info.update(merged_dynamic_partitions_dict)
225*9e94795aSAndroid Build Coastguard Worker  # Ensure that add_img_to_target_files rebuilds super split images for
226*9e94795aSAndroid Build Coastguard Worker  # devices that retrofit dynamic partitions. This flag may have been set to
227*9e94795aSAndroid Build Coastguard Worker  # false in the partial builds to prevent duplicate building of super.img.
228*9e94795aSAndroid Build Coastguard Worker  OPTIONS.merged_misc_info['build_super_partition'] = 'true'
229*9e94795aSAndroid Build Coastguard Worker
230*9e94795aSAndroid Build Coastguard Worker
231*9e94795aSAndroid Build Coastguard Workerdef MergePackageKeys(framework_meta_dir, vendor_meta_dir, merged_meta_dir,
232*9e94795aSAndroid Build Coastguard Worker                     file_name):
233*9e94795aSAndroid Build Coastguard Worker  """Merges APK/APEX key list files."""
234*9e94795aSAndroid Build Coastguard Worker
235*9e94795aSAndroid Build Coastguard Worker  if file_name not in ('apkcerts.txt', 'apexkeys.txt'):
236*9e94795aSAndroid Build Coastguard Worker    raise ExternalError(
237*9e94795aSAndroid Build Coastguard Worker        'Unexpected file_name provided to merge_package_keys_txt: %s',
238*9e94795aSAndroid Build Coastguard Worker        file_name)
239*9e94795aSAndroid Build Coastguard Worker
240*9e94795aSAndroid Build Coastguard Worker  def read_helper(d):
241*9e94795aSAndroid Build Coastguard Worker    temp = {}
242*9e94795aSAndroid Build Coastguard Worker    with open(os.path.join(d, file_name)) as f:
243*9e94795aSAndroid Build Coastguard Worker      for line in f.read().splitlines():
244*9e94795aSAndroid Build Coastguard Worker        line = line.strip()
245*9e94795aSAndroid Build Coastguard Worker        if line:
246*9e94795aSAndroid Build Coastguard Worker          name_search = MODULE_KEY_PATTERN.search(line.split()[0])
247*9e94795aSAndroid Build Coastguard Worker          temp[name_search.group(1)] = line
248*9e94795aSAndroid Build Coastguard Worker    return temp
249*9e94795aSAndroid Build Coastguard Worker
250*9e94795aSAndroid Build Coastguard Worker  framework_dict = read_helper(framework_meta_dir)
251*9e94795aSAndroid Build Coastguard Worker  vendor_dict = read_helper(vendor_meta_dir)
252*9e94795aSAndroid Build Coastguard Worker  merged_dict = {}
253*9e94795aSAndroid Build Coastguard Worker
254*9e94795aSAndroid Build Coastguard Worker  def filter_into_merged_dict(item_dict, partition_set):
255*9e94795aSAndroid Build Coastguard Worker    for key, value in item_dict.items():
256*9e94795aSAndroid Build Coastguard Worker      tag_search = PARTITION_TAG_PATTERN.search(value)
257*9e94795aSAndroid Build Coastguard Worker
258*9e94795aSAndroid Build Coastguard Worker      if tag_search is None:
259*9e94795aSAndroid Build Coastguard Worker        raise ValueError('Entry missing partition tag: %s' % value)
260*9e94795aSAndroid Build Coastguard Worker
261*9e94795aSAndroid Build Coastguard Worker      partition_tag = tag_search.group(1)
262*9e94795aSAndroid Build Coastguard Worker
263*9e94795aSAndroid Build Coastguard Worker      if partition_tag in partition_set:
264*9e94795aSAndroid Build Coastguard Worker        if key in merged_dict:
265*9e94795aSAndroid Build Coastguard Worker          if OPTIONS.allow_duplicate_apkapex_keys:
266*9e94795aSAndroid Build Coastguard Worker            # TODO(b/150582573) Always raise on duplicates.
267*9e94795aSAndroid Build Coastguard Worker            logger.warning('Duplicate key %s' % key)
268*9e94795aSAndroid Build Coastguard Worker            continue
269*9e94795aSAndroid Build Coastguard Worker          else:
270*9e94795aSAndroid Build Coastguard Worker            raise ValueError('Duplicate key %s' % key)
271*9e94795aSAndroid Build Coastguard Worker
272*9e94795aSAndroid Build Coastguard Worker        merged_dict[key] = value
273*9e94795aSAndroid Build Coastguard Worker
274*9e94795aSAndroid Build Coastguard Worker  # Prioritize framework keys first.
275*9e94795aSAndroid Build Coastguard Worker  # Duplicate keys from vendor are an error, or ignored.
276*9e94795aSAndroid Build Coastguard Worker  filter_into_merged_dict(framework_dict, OPTIONS.framework_partition_set)
277*9e94795aSAndroid Build Coastguard Worker  filter_into_merged_dict(vendor_dict, OPTIONS.vendor_partition_set)
278*9e94795aSAndroid Build Coastguard Worker
279*9e94795aSAndroid Build Coastguard Worker  # The following code is similar to WriteSortedData, but different enough
280*9e94795aSAndroid Build Coastguard Worker  # that we couldn't use that function. We need the output to be sorted by the
281*9e94795aSAndroid Build Coastguard Worker  # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
282*9e94795aSAndroid Build Coastguard Worker  # allows the sort to be consistent with the framework/vendor input data and
283*9e94795aSAndroid Build Coastguard Worker  # eases comparison of input data with merged data.
284*9e94795aSAndroid Build Coastguard Worker  with open(os.path.join(merged_meta_dir, file_name), 'w') as output:
285*9e94795aSAndroid Build Coastguard Worker    for key, value in sorted(merged_dict.items()):
286*9e94795aSAndroid Build Coastguard Worker      output.write(value + '\n')
287*9e94795aSAndroid Build Coastguard Worker
288*9e94795aSAndroid Build Coastguard Worker
289*9e94795aSAndroid Build Coastguard Workerdef CopyNamedFileContexts(framework_meta_dir, vendor_meta_dir, merged_meta_dir):
290*9e94795aSAndroid Build Coastguard Worker  """Creates named copies of each partial build's file_contexts.bin.
291*9e94795aSAndroid Build Coastguard Worker
292*9e94795aSAndroid Build Coastguard Worker  Used when regenerating images from the partial build.
293*9e94795aSAndroid Build Coastguard Worker  """
294*9e94795aSAndroid Build Coastguard Worker
295*9e94795aSAndroid Build Coastguard Worker  def copy_fc_file(source_dir, file_name):
296*9e94795aSAndroid Build Coastguard Worker    for name in (file_name, 'file_contexts.bin'):
297*9e94795aSAndroid Build Coastguard Worker      fc_path = os.path.join(source_dir, name)
298*9e94795aSAndroid Build Coastguard Worker      if os.path.exists(fc_path):
299*9e94795aSAndroid Build Coastguard Worker        shutil.copyfile(fc_path, os.path.join(merged_meta_dir, file_name))
300*9e94795aSAndroid Build Coastguard Worker        return
301*9e94795aSAndroid Build Coastguard Worker    raise ValueError('Missing file_contexts file from %s: %s', source_dir,
302*9e94795aSAndroid Build Coastguard Worker                     file_name)
303*9e94795aSAndroid Build Coastguard Worker
304*9e94795aSAndroid Build Coastguard Worker  copy_fc_file(framework_meta_dir, 'framework_file_contexts.bin')
305*9e94795aSAndroid Build Coastguard Worker  copy_fc_file(vendor_meta_dir, 'vendor_file_contexts.bin')
306*9e94795aSAndroid Build Coastguard Worker
307*9e94795aSAndroid Build Coastguard Worker  # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
308*9e94795aSAndroid Build Coastguard Worker  # depending on which dictionary the key came from.
309*9e94795aSAndroid Build Coastguard Worker  # Only the file basename is required because all selinux_fc properties are
310*9e94795aSAndroid Build Coastguard Worker  # replaced with the full path to the file under META/ when misc_info.txt is
311*9e94795aSAndroid Build Coastguard Worker  # loaded from target files for repacking. See common.py LoadInfoDict().
312*9e94795aSAndroid Build Coastguard Worker  for key in OPTIONS.vendor_misc_info:
313*9e94795aSAndroid Build Coastguard Worker    if key.endswith('_selinux_fc'):
314*9e94795aSAndroid Build Coastguard Worker      OPTIONS.merged_misc_info[key] = 'vendor_file_contexts.bin'
315*9e94795aSAndroid Build Coastguard Worker  for key in OPTIONS.framework_misc_info:
316*9e94795aSAndroid Build Coastguard Worker    if key.endswith('_selinux_fc'):
317*9e94795aSAndroid Build Coastguard Worker      OPTIONS.merged_misc_info[key] = 'framework_file_contexts.bin'
318*9e94795aSAndroid Build Coastguard Worker
319*9e94795aSAndroid Build Coastguard Worker
320*9e94795aSAndroid Build Coastguard Workerdef UpdateCareMapImageSizeProps(images_dir):
321*9e94795aSAndroid Build Coastguard Worker  """Sets <partition>_image_size props in misc_info.
322*9e94795aSAndroid Build Coastguard Worker
323*9e94795aSAndroid Build Coastguard Worker  add_images_to_target_files uses these props to generate META/care_map.pb.
324*9e94795aSAndroid Build Coastguard Worker  Regenerated images will have this property set during regeneration.
325*9e94795aSAndroid Build Coastguard Worker
326*9e94795aSAndroid Build Coastguard Worker  However, images copied directly from input partial target files packages
327*9e94795aSAndroid Build Coastguard Worker  need this value calculated here.
328*9e94795aSAndroid Build Coastguard Worker  """
329*9e94795aSAndroid Build Coastguard Worker  for partition in common.PARTITIONS_WITH_CARE_MAP:
330*9e94795aSAndroid Build Coastguard Worker    image_path = os.path.join(images_dir, '{}.img'.format(partition))
331*9e94795aSAndroid Build Coastguard Worker    if os.path.exists(image_path):
332*9e94795aSAndroid Build Coastguard Worker      partition_size = sparse_img.GetImagePartitionSize(image_path)
333*9e94795aSAndroid Build Coastguard Worker      image_props = build_image.ImagePropFromGlobalDict(
334*9e94795aSAndroid Build Coastguard Worker          OPTIONS.merged_misc_info, partition)
335*9e94795aSAndroid Build Coastguard Worker      verity_image_builder = verity_utils.CreateVerityImageBuilder(image_props)
336*9e94795aSAndroid Build Coastguard Worker      image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
337*9e94795aSAndroid Build Coastguard Worker      OPTIONS.merged_misc_info['{}_image_size'.format(partition)] = image_size
338