blob: 16cab4fbd5d6cbf50e6c1c03459ca1634a0d1932 [file] [log] [blame]
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001#!/usr/bin/env python
2#
3# Copyright (C) 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
Daniel Norman4cc9df62019-07-18 10:11:07 -070016#
17"""This script merges two partial target files packages.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080018
Daniel Normandbbf5a32020-10-22 16:03:32 -070019One input package contains framework files, and the other contains vendor files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080020
Daniel Normandbbf5a32020-10-22 16:03:32 -070021This script produces a complete, merged target files package:
22 - This package can be used to generate a flashable IMG package.
23 See --output-img.
24 - This package can be used to generate an OTA package. See --output-ota.
25 - The merged package is checked for compatibility between the two inputs.
26
27Usage: merge_target_files [args]
Bill Peckhame9eb5f92019-02-01 15:52:10 -080028
Daniel Normand5d70ea2019-06-05 15:13:43 -070029 --framework-target-files framework-target-files-zip-archive
30 The input target files package containing framework bits. This is a zip
Bill Peckhame9eb5f92019-02-01 15:52:10 -080031 archive.
32
Daniel Normand5d70ea2019-06-05 15:13:43 -070033 --framework-item-list framework-item-list-file
Daniel Norman2c99c5b2019-03-07 13:01:48 -080034 The optional path to a newline-separated config file that replaces the
Daniel Normand5d70ea2019-06-05 15:13:43 -070035 contents of DEFAULT_FRAMEWORK_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080036
Daniel Normand5d70ea2019-06-05 15:13:43 -070037 --framework-misc-info-keys framework-misc-info-keys-file
Daniel Norman2c99c5b2019-03-07 13:01:48 -080038 The optional path to a newline-separated config file that replaces the
Daniel Normand5d70ea2019-06-05 15:13:43 -070039 contents of DEFAULT_FRAMEWORK_MISC_INFO_KEYS if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080040
Daniel Normand5d70ea2019-06-05 15:13:43 -070041 --vendor-target-files vendor-target-files-zip-archive
42 The input target files package containing vendor bits. This is a zip
Bill Peckhame9eb5f92019-02-01 15:52:10 -080043 archive.
44
Daniel Normand5d70ea2019-06-05 15:13:43 -070045 --vendor-item-list vendor-item-list-file
Daniel Norman2c99c5b2019-03-07 13:01:48 -080046 The optional path to a newline-separated config file that replaces the
Daniel Normand5d70ea2019-06-05 15:13:43 -070047 contents of DEFAULT_VENDOR_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080048
Bill Peckhame9eb5f92019-02-01 15:52:10 -080049 --output-target-files output-target-files-package
Daniel Normanfdb38812019-04-15 09:47:24 -070050 If provided, the output merged target files package. Also a zip archive.
51
52 --output-dir output-directory
53 If provided, the destination directory for saving merged files. Requires
54 the --output-item-list flag.
55 Can be provided alongside --output-target-files, or by itself.
56
57 --output-item-list output-item-list-file.
58 The optional path to a newline-separated config file that specifies the
59 file patterns to copy into the --output-dir. Required if providing
60 the --output-dir flag.
Daniel Normana4911da2019-03-15 14:36:21 -070061
Daniel Norman3b64ce12019-04-16 16:11:35 -070062 --output-ota output-ota-package
63 The output ota package. This is a zip archive. Use of this flag may
64 require passing the --path common flag; see common.py.
65
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070066 --output-img output-img-package
67 The output img package, suitable for use with 'fastboot update'. Use of
68 this flag may require passing the --path common flag; see common.py.
69
Daniel Normanf0318252019-04-15 11:34:56 -070070 --output-super-empty output-super-empty-image
71 If provided, creates a super_empty.img file from the merged target
72 files package and saves it at this path.
73
Daniel Normana4911da2019-03-15 14:36:21 -070074 --rebuild_recovery
Bill Peckhame868aec2019-09-17 17:06:47 -070075 Deprecated; does nothing.
Bill Peckham364c1cc2019-03-29 18:27:23 -070076
Daniel Normanb0c75912020-09-24 14:30:21 -070077 --allow-duplicate-apkapex-keys
78 If provided, duplicate APK/APEX keys are ignored and the value from the
79 framework is used.
80
Bill Peckham364c1cc2019-03-29 18:27:23 -070081 --keep-tmp
82 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080083"""
84
85from __future__ import print_function
86
Bill Peckhame9eb5f92019-02-01 15:52:10 -080087import fnmatch
Daniel Normand3351562020-10-29 12:33:11 -070088import json
Bill Peckhame9eb5f92019-02-01 15:52:10 -080089import logging
90import os
Bill Peckham19c3feb2020-03-20 18:31:43 -070091import re
Daniel Normanfdb38812019-04-15 09:47:24 -070092import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -070093import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -080094import sys
95import zipfile
Daniel Norman48603ff2021-02-22 15:15:24 -080096from xml.etree import ElementTree
Bill Peckhame9eb5f92019-02-01 15:52:10 -080097
Bill Peckhame9eb5f92019-02-01 15:52:10 -080098import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070099import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -0700100import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -0700101import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700102import img_from_target_files
Daniel Normanb8d52a22020-10-26 17:55:00 -0700103import find_shareduid_violation
Daniel Norman3b64ce12019-04-16 16:11:35 -0700104import ota_from_target_files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800105
106logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -0700107
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800108OPTIONS = common.OPTIONS
Bill Peckhamcb848172020-04-03 12:50:47 -0700109# Always turn on verbose logging.
110OPTIONS.verbose = True
Daniel Normand5d70ea2019-06-05 15:13:43 -0700111OPTIONS.framework_target_files = None
112OPTIONS.framework_item_list = None
113OPTIONS.framework_misc_info_keys = None
114OPTIONS.vendor_target_files = None
115OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800116OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700117OPTIONS.output_dir = None
118OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700119OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700120OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700121OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700122# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700123OPTIONS.rebuild_recovery = False
Daniel Normanb0c75912020-09-24 14:30:21 -0700124# TODO(b/150582573): Remove this option.
125OPTIONS.allow_duplicate_apkapex_keys = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800126OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800127
Bill Peckham19c3feb2020-03-20 18:31:43 -0700128# In an item list (framework or vendor), we may see entries that select whole
129# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the
130# system partition). The following regex matches this and extracts the
131# partition name.
132
133PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$')
134
Bill Peckham5c7b0342020-04-03 15:36:23 -0700135# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
136# the file. We use these partition tags to filter the entries in those files
137# from the two different target files packages to produce a merged apexkeys.txt
138# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
139# like this: 'partition="product"'. We use the group syntax grab the value of
140# the tag. We use non-greedy matching in case there are other fields on the
141# same line.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700142
Bill Peckham5c7b0342020-04-03 15:36:23 -0700143PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700144
145# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
146# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
147
148MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
149
Daniel Normand5d70ea2019-06-05 15:13:43 -0700150# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
151# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800152# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700153# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800154
Daniel Normand5d70ea2019-06-05 15:13:43 -0700155DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800156 'META/apkcerts.txt',
157 'META/filesystem_config.txt',
158 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800159 'META/update_engine_config.txt',
160 'PRODUCT/*',
161 'ROOT/*',
162 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700163)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800164
Daniel Normand5d70ea2019-06-05 15:13:43 -0700165# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700166# framework instance of META/misc_info.txt. The remaining keys should come
167# from the vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800168
Daniel Normand5d70ea2019-06-05 15:13:43 -0700169DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800170 'avb_system_hashtree_enable',
171 'avb_system_add_hashtree_footer_args',
172 'avb_system_key_path',
173 'avb_system_algorithm',
174 'avb_system_rollback_index_location',
175 'avb_product_hashtree_enable',
176 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900177 'avb_system_ext_hashtree_enable',
178 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800179 'system_root_image',
180 'root_dir',
181 'ab_update',
182 'default_system_dev_certificate',
183 'system_size',
Chris Gross203191b2020-05-30 02:39:12 +0000184 'building_system_image',
185 'building_system_ext_image',
186 'building_product_image',
Daniel Normanedf12472019-05-22 10:47:08 -0700187)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800188
Daniel Normand5d70ea2019-06-05 15:13:43 -0700189# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
190# vendor target files package as is, meaning these items will land in the output
191# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800192# files package.
193
Daniel Normand5d70ea2019-06-05 15:13:43 -0700194DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800195 'META/boot_filesystem_config.txt',
196 'META/otakeys.txt',
197 'META/releasetools.py',
198 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800199 'BOOT/*',
200 'DATA/*',
201 'ODM/*',
202 'OTA/android-info.txt',
203 'PREBUILT_IMAGES/*',
204 'RADIO/*',
205 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700206)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800207
Daniel Normanedf12472019-05-22 10:47:08 -0700208# The merge config lists should not attempt to extract items from both
209# builds for any of the following partitions. The partitions in
210# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700211# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700212
213SINGLE_BUILD_PARTITIONS = (
214 'BOOT/',
215 'DATA/',
216 'ODM/',
217 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900218 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700219 'RADIO/',
220 'RECOVERY/',
221 'ROOT/',
222 'SYSTEM/',
223 'SYSTEM_OTHER/',
224 'VENDOR/',
Yifan Hongcfb917a2020-05-07 14:58:20 -0700225 'VENDOR_DLKM/',
Yifan Hongf496f1b2020-07-15 16:52:59 -0700226 'ODM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700227)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800228
229
Chris Grossfabf50a2019-05-02 12:42:09 -0700230def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700231 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700232
Tao Bao2ad4b822019-06-27 16:52:12 -0700233 This function sorts the contents of the list or dict and then writes the
234 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700235
236 Args:
237 data: The list or dict to sort and write.
238 path: Path to the file to write the sorted values to. The file at path will
239 be overridden if it exists.
240 """
241 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700242 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700243 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
244 data, dict) else '{}\n'.format(entry)
245 output.write(out_str)
246
247
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800248def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700249 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800250
251 This function extracts from the specified target files zip archive into the
252 specified temporary directory, the items specified in the extract item list.
253
254 Args:
255 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800256 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700257 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800258 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800259 """
260
261 logger.info('extracting from %s', target_files)
262
263 # Filter the extract_item_list to remove any items that do not exist in the
264 # zip file. Otherwise, the extraction step will fail.
265
Daniel Norman4cc9df62019-07-18 10:11:07 -0700266 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800267 target_files_namelist = target_files_zipfile.namelist()
268
269 filtered_extract_item_list = []
270 for pattern in extract_item_list:
271 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
272 if not matching_namelist:
273 logger.warning('no match for %s', pattern)
274 else:
275 filtered_extract_item_list.append(pattern)
276
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800277 # Extract from target_files into target_files_temp_dir the
278 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800279
Daniel Normane5b134a2019-04-17 14:54:06 -0700280 common.UnzipToDir(target_files, target_files_temp_dir,
281 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800282
283
Daniel Normanfdb38812019-04-15 09:47:24 -0700284def copy_items(from_dir, to_dir, patterns):
285 """Similar to extract_items() except uses an input dir instead of zip."""
286 file_paths = []
287 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700288 file_paths.extend(
289 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
290 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700291
292 filtered_file_paths = set()
293 for pattern in patterns:
294 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
295
296 for file_path in filtered_file_paths:
297 original_file_path = os.path.join(from_dir, file_path)
298 copied_file_path = os.path.join(to_dir, file_path)
299 copied_file_dir = os.path.dirname(copied_file_path)
300 if not os.path.exists(copied_file_dir):
301 os.makedirs(copied_file_dir)
302 if os.path.islink(original_file_path):
303 os.symlink(os.readlink(original_file_path), copied_file_path)
304 else:
305 shutil.copyfile(original_file_path, copied_file_path)
306
307
Daniel Normand5d70ea2019-06-05 15:13:43 -0700308def validate_config_lists(framework_item_list, framework_misc_info_keys,
309 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700310 """Performs validations on the merge config lists.
311
312 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700313 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700314 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700315 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700316 instance of META/misc_info.txt. The remaining keys should come from the
317 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700318 vendor_item_list: The list of items to extract from the partial vendor
319 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700320
321 Returns:
322 False if a validation fails, otherwise true.
323 """
Daniel Normanedf12472019-05-22 10:47:08 -0700324 has_error = False
325
Daniel Normand5d70ea2019-06-05 15:13:43 -0700326 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
327 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700328
Daniel Normand5d70ea2019-06-05 15:13:43 -0700329 combined_item_set = set(framework_item_list)
330 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700331
332 # Check that the merge config lists are not missing any item specified
333 # by the default config lists.
334 difference = default_combined_item_set.difference(combined_item_set)
335 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700336 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700337 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700338 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700339 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700340 has_error = True
341
Daniel Normandbbf5a32020-10-22 16:03:32 -0700342 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700343 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700344 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
345 in_framework = (
346 any(item.startswith(partition) for item in framework_item_list) or
347 image_path in framework_item_list)
348 in_vendor = (
349 any(item.startswith(partition) for item in vendor_item_list) or
350 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700351 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700352 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700353 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900354 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700355 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700356 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700357
Daniel Normand5d70ea2019-06-05 15:13:43 -0700358 if ('dynamic_partition_list' in framework_misc_info_keys) or (
Daniel Norman2d7989a2021-04-05 17:40:47 +0000359 'super_partition_groups' in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700360 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700361 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700362 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700363
Daniel Normanedf12472019-05-22 10:47:08 -0700364 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700365
366
Daniel Normand5d70ea2019-06-05 15:13:43 -0700367def process_ab_partitions_txt(framework_target_files_temp_dir,
368 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700369 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700370 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800371
Tao Bao2ad4b822019-06-27 16:52:12 -0700372 This function merges the contents of the META/ab_partitions.txt files from the
373 framework directory and the vendor directory, placing the merged result in the
374 output directory. The precondition in that the files are already extracted.
375 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700376 merged content. The format for each ab_partitions.txt is one partition name
377 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800378
379 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700380 framework_target_files_temp_dir: The name of a directory containing the
381 special items extracted from the framework target files package.
382 vendor_target_files_temp_dir: The name of a directory containing the special
383 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700384 output_target_files_temp_dir: The name of a directory that will be used to
385 create the output target files package after all the special cases are
386 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800387 """
388
Daniel Normand5d70ea2019-06-05 15:13:43 -0700389 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
390 'META', 'ab_partitions.txt')
391
392 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700393 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800394
Daniel Normand5d70ea2019-06-05 15:13:43 -0700395 with open(framework_ab_partitions_txt) as f:
396 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800397
Daniel Normand5d70ea2019-06-05 15:13:43 -0700398 with open(vendor_ab_partitions_txt) as f:
399 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800400
Daniel Normand5d70ea2019-06-05 15:13:43 -0700401 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800402
Daniel Normane5b134a2019-04-17 14:54:06 -0700403 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
404 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800405
Chris Grossfabf50a2019-05-02 12:42:09 -0700406 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800407
408
Daniel Normand5d70ea2019-06-05 15:13:43 -0700409def process_misc_info_txt(framework_target_files_temp_dir,
410 vendor_target_files_temp_dir,
411 output_target_files_temp_dir,
412 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700413 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800414
415 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700416 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800417 output directory. The precondition in that the files are already extracted.
418 The post condition is that the output META/misc_info.txt contains the merged
419 content.
420
421 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700422 framework_target_files_temp_dir: The name of a directory containing the
423 special items extracted from the framework target files package.
424 vendor_target_files_temp_dir: The name of a directory containing the special
425 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700426 output_target_files_temp_dir: The name of a directory that will be used to
427 create the output target files package after all the special cases are
428 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700429 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700430 instance of META/misc_info.txt. The remaining keys should come from the
431 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800432 """
433
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900434 misc_info_path = ['META', 'misc_info.txt']
435 framework_dict = common.LoadDictionaryFromFile(
436 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800437
Daniel Normand5d70ea2019-06-05 15:13:43 -0700438 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800439
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900440 merged_dict = common.LoadDictionaryFromFile(
441 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800442
Daniel Normand5d70ea2019-06-05 15:13:43 -0700443 # Replace certain values in merged_dict with values from
444 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800445
Daniel Normand5d70ea2019-06-05 15:13:43 -0700446 for key in framework_misc_info_keys:
447 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800448
Daniel Norman19b9fe92019-03-19 14:48:02 -0700449 # Merge misc info keys used for Dynamic Partitions.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700450 if (merged_dict.get('use_dynamic_partitions') == 'true') and (
Daniel Norman2d7989a2021-04-05 17:40:47 +0000451 framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700452 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800453 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700454 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700455 # Ensure that add_img_to_target_files rebuilds super split images for
456 # devices that retrofit dynamic partitions. This flag may have been set to
457 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700458 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700459
Daniel Norman38888d32020-11-19 14:51:15 -0800460 # If AVB is enabled then ensure that we build vbmeta.img.
461 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
462 # skip building an incomplete vbmeta.img.
463 if merged_dict.get('avb_enable') == 'true':
464 merged_dict['avb_building_vbmeta_image'] = 'true'
465
Daniel Normand5d70ea2019-06-05 15:13:43 -0700466 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700467 # depending on which dictionary the key came from.
468 # Only the file basename is required because all selinux_fc properties are
469 # replaced with the full path to the file under META/ when misc_info.txt is
470 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700471 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700472 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700473 merged_dict[key] = 'vendor_file_contexts.bin'
474 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700475 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700476 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700477
Daniel Normane5b134a2019-04-17 14:54:06 -0700478 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
479 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700480 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800481
482
Daniel Normand5d70ea2019-06-05 15:13:43 -0700483def process_dynamic_partitions_info_txt(framework_target_files_dir,
484 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700485 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700486 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700487
488 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700489 files from the framework directory and the vendor directory, placing the
490 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700491
Daniel Normand5d70ea2019-06-05 15:13:43 -0700492 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700493 directory does not exist.
494
495 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700496 framework_target_files_dir: The name of a directory containing the special
497 items extracted from the framework target files package.
498 vendor_target_files_dir: The name of a directory containing the special
499 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700500 output_target_files_dir: The name of a directory that will be used to create
501 the output target files package after all the special cases are processed.
502 """
503
504 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700505 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700506 'dynamic_partitions_info.txt')):
507 return
508
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900509 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700510
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900511 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
512 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
513 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
514 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700515
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700516 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700517 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800518 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700519
520 output_dynamic_partitions_info_txt = os.path.join(
521 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700522 write_sorted_data(
523 data=merged_dynamic_partitions_dict,
524 path=output_dynamic_partitions_info_txt)
525
526
Bill Peckham19c3feb2020-03-20 18:31:43 -0700527def item_list_to_partition_set(item_list):
528 """Converts a target files item list to a partition set.
529
530 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
531 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
532 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
533 contents of a partition of the same name. Other items in the list, such as the
534 'OTA' example contain metadata. This function iterates such a list, returning
535 a set that contains the partition entries.
536
537 Args:
538 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700539
Bill Peckham19c3feb2020-03-20 18:31:43 -0700540 Returns:
541 A set of partitions extracted from the list of items.
542 """
543
544 partition_set = set()
545
546 for item in item_list:
547 match = PARTITION_ITEM_PATTERN.search(item.strip())
548 partition_tag = match.group(1).lower() if match else None
549
550 if partition_tag:
551 partition_set.add(partition_tag)
552
553 return partition_set
554
555
Daniel Normand5d70ea2019-06-05 15:13:43 -0700556def process_apex_keys_apk_certs_common(framework_target_files_dir,
557 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700558 output_target_files_dir,
559 framework_partition_set,
560 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700561 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700562
563 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700564 META/apkcerts.txt files from the framework directory and the vendor directory,
565 placing the merged result in the output directory. The precondition in that
566 the files are already extracted. The post condition is that the output
567 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700568
569 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700570 framework_target_files_dir: The name of a directory containing the special
571 items extracted from the framework target files package.
572 vendor_target_files_dir: The name of a directory containing the special
573 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700574 output_target_files_dir: The name of a directory that will be used to create
575 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700576 framework_partition_set: Partitions that are considered framework
577 partitions. Used to filter apexkeys.txt and apkcerts.txt.
578 vendor_partition_set: Partitions that are considered vendor partitions. Used
579 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700580 file_name: The name of the file to merge. One of apkcerts.txt or
581 apexkeys.txt.
582 """
583
584 def read_helper(d):
585 temp = {}
586 file_path = os.path.join(d, 'META', file_name)
587 with open(file_path) as f:
588 for line in f:
589 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700590 name = line.split()[0]
591 match = MODULE_KEY_PATTERN.search(name)
592 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700593 return temp
594
Daniel Normand5d70ea2019-06-05 15:13:43 -0700595 framework_dict = read_helper(framework_target_files_dir)
596 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700597 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700598
Bill Peckham19c3feb2020-03-20 18:31:43 -0700599 def filter_into_merged_dict(item_dict, partition_set):
600 for key, value in item_dict.items():
601 match = PARTITION_TAG_PATTERN.search(value)
602
603 if match is None:
604 raise ValueError('Entry missing partition tag: %s' % value)
605
606 partition_tag = match.group(1)
607
608 if partition_tag in partition_set:
609 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700610 if OPTIONS.allow_duplicate_apkapex_keys:
611 # TODO(b/150582573) Always raise on duplicates.
612 logger.warning('Duplicate key %s' % key)
613 continue
614 else:
615 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700616
617 merged_dict[key] = value
618
619 filter_into_merged_dict(framework_dict, framework_partition_set)
620 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700621
622 output_file = os.path.join(output_target_files_dir, 'META', file_name)
623
Bill Peckham19c3feb2020-03-20 18:31:43 -0700624 # The following code is similar to write_sorted_data, but different enough
625 # that we couldn't use that function. We need the output to be sorted by the
626 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
627 # allows the sort to be consistent with the framework/vendor input data and
628 # eases comparison of input data with merged data.
629 with open(output_file, 'w') as output:
630 for key in sorted(merged_dict.keys()):
631 out_str = merged_dict[key] + '\n'
632 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700633
634
Daniel Normand5d70ea2019-06-05 15:13:43 -0700635def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700636 output_target_files_dir):
637 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700638 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
639 'framework_file_contexts.bin')
640 if not os.path.exists(framework_fc_path):
641 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
642 'file_contexts.bin')
643 if not os.path.exists(framework_fc_path):
644 raise ValueError('Missing framework file_contexts.bin.')
645 shutil.copyfile(
646 framework_fc_path,
647 os.path.join(output_target_files_dir, 'META',
648 'framework_file_contexts.bin'))
649
650 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
651 'vendor_file_contexts.bin')
652 if not os.path.exists(vendor_fc_path):
653 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700654 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700655 if not os.path.exists(vendor_fc_path):
656 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700657 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700658 vendor_fc_path,
659 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700660
661
Daniel Norman48603ff2021-02-22 15:15:24 -0800662def compile_split_sepolicy(product_out, partition_map, output_policy):
663 """Uses secilc to compile a split sepolicy file.
664
665 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
666
667 Args:
668 product_out: PRODUCT_OUT directory, containing partition directories.
669 partition_map: A map of partition name -> relative path within product_out.
670 output_policy: The name of the output policy created by secilc.
671
672 Returns:
673 A command list that can be executed to create the compiled sepolicy.
674 """
675
676 def get_file(partition, path):
677 if partition not in partition_map:
678 logger.warning('Cannot load SEPolicy files for missing partition %s',
679 partition)
680 return None
681 return os.path.join(product_out, partition_map[partition], path)
682
683 # Load the kernel sepolicy version from the FCM. This is normally provided
684 # directly to selinux.cpp as a build flag, but is also available in this file.
685 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
686 if not fcm_file or not os.path.exists(fcm_file):
687 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
688 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
689 'sepolicy/kernel-sepolicy-version').text
690
691 # Load the vendor's plat sepolicy version. This is the version used for
692 # locating sepolicy mapping files.
693 vendor_plat_version_file = get_file('vendor',
694 'etc/selinux/plat_sepolicy_vers.txt')
695 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000696 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800697 raise ExternalError('Missing required sepolicy file %s',
698 vendor_plat_version_file)
699 with open(vendor_plat_version_file) as f:
700 vendor_plat_version = f.read().strip()
701
702 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
703 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
704 cmd.extend(['-c', kernel_sepolicy_version])
705 cmd.extend(['-o', output_policy])
706 cmd.extend(['-f', '/dev/null'])
707
708 required_policy_files = (
709 ('system', 'etc/selinux/plat_sepolicy.cil'),
710 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
711 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
712 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
713 )
714 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
715 required_policy_files)):
716 if not policy or not os.path.exists(policy):
717 raise ExternalError('Missing required sepolicy file %s', policy)
718 cmd.append(policy)
719
720 optional_policy_files = (
721 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
722 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
723 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
724 ('product', 'etc/selinux/product_sepolicy.cil'),
725 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
726 ('odm', 'etc/selinux/odm_sepolicy.cil'),
727 )
728 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
729 optional_policy_files)):
730 if policy and os.path.exists(policy):
731 cmd.append(policy)
732
733 return cmd
734
735
Daniel Normand5d70ea2019-06-05 15:13:43 -0700736def process_special_cases(framework_target_files_temp_dir,
737 vendor_target_files_temp_dir,
738 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700739 framework_misc_info_keys, framework_partition_set,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700740 vendor_partition_set):
Tao Bao2ad4b822019-06-27 16:52:12 -0700741 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800742
743 Certain files in the output target files package require special-case
744 processing. This function performs all that special-case processing.
745
746 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700747 framework_target_files_temp_dir: The name of a directory containing the
748 special items extracted from the framework target files package.
749 vendor_target_files_temp_dir: The name of a directory containing the special
750 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700751 output_target_files_temp_dir: The name of a directory that will be used to
752 create the output target files package after all the special cases are
753 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700754 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700755 instance of META/misc_info.txt. The remaining keys should come from the
756 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700757 framework_partition_set: Partitions that are considered framework
758 partitions. Used to filter apexkeys.txt and apkcerts.txt.
759 vendor_partition_set: Partitions that are considered vendor partitions. Used
760 to filter apexkeys.txt and apkcerts.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800761 """
762
Daniel Normand5d70ea2019-06-05 15:13:43 -0700763 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700764 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700765 framework_target_files_temp_dir=framework_target_files_temp_dir,
766 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700767 output_target_files_temp_dir=output_target_files_temp_dir)
768
Daniel Norman72c626f2019-05-13 15:58:14 -0700769 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700770 framework_target_files_dir=framework_target_files_temp_dir,
771 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700772 output_target_files_dir=output_target_files_temp_dir)
773
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800774 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700775 framework_target_files_temp_dir=framework_target_files_temp_dir,
776 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800777 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700778 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800779
Daniel Normana61cde02019-05-03 14:19:13 -0700780 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700781 framework_target_files_dir=framework_target_files_temp_dir,
782 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700783 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700784
Chris Grossfabf50a2019-05-02 12:42:09 -0700785 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700786 framework_target_files_dir=framework_target_files_temp_dir,
787 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700788 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700789 framework_partition_set=framework_partition_set,
790 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700791 file_name='apkcerts.txt')
792
793 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700794 framework_target_files_dir=framework_target_files_temp_dir,
795 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700796 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700797 framework_partition_set=framework_partition_set,
798 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700799 file_name='apexkeys.txt')
800
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800801
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900802def create_merged_package(temp_dir, framework_target_files, framework_item_list,
803 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700804 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700805 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800806
807 Args:
808 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700809 input target files packages, and also a scratch directory that we use for
810 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700811 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700812 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700813 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700814 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700815 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700816 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700817 vendor_target_files: The name of the zip archive containing the vendor
818 partial target files package.
819 vendor_item_list: The list of items to extract from the partial vendor
820 target files package as is, meaning these items will land in the output
821 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700822 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -0700823 framework_misc_info_keys: A list of keys to obtain from the framework
824 instance of META/misc_info.txt. The remaining keys should come from the
825 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700826 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700827 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800828
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900829 Returns:
830 Path to merged package under temp directory.
831 """
Daniel Normandbbf5a32020-10-22 16:03:32 -0700832 # Extract "as is" items from the input framework and vendor partial target
833 # files packages directly into the output temporary directory, since these items
834 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800835
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800836 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -0800837 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700838 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800839 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700840 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -0800841 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700842 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800843 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700844 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800845
Daniel Normandbbf5a32020-10-22 16:03:32 -0700846 # Perform special case processing on META/* items.
847 # After this function completes successfully, all the files we need to create
848 # the output target files package are in place.
849 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
850 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700851 extract_items(
852 target_files=framework_target_files,
853 target_files_temp_dir=framework_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700854 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800855 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700856 target_files=vendor_target_files,
857 target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700858 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800859 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700860 framework_target_files_temp_dir=framework_target_files_temp_dir,
861 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800862 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700863 framework_misc_info_keys=framework_misc_info_keys,
864 framework_partition_set=item_list_to_partition_set(framework_item_list),
865 vendor_partition_set=item_list_to_partition_set(vendor_item_list))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800866
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900867 return output_target_files_temp_dir
868
869
870def generate_images(target_files_dir, rebuild_recovery):
871 """Generate images from target files.
872
873 This function takes merged output temporary directory and create images
874 from it.
875
876 Args:
877 target_files_dir: Path to merged temp directory.
878 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
879 devices and write it to the system image.
880 """
881
882 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800883
Daniel Normandbbf5a32020-10-22 16:03:32 -0700884 add_img_args = [
885 '--verbose',
886 '--add_missing',
887 ]
Bill Peckhame868aec2019-09-17 17:06:47 -0700888 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700889 if rebuild_recovery:
890 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900891 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800892
893 add_img_to_target_files.main(add_img_args)
894
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900895
896def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700897 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900898
899 Args:
900 target_dir: Path to the target file package which contains misc_info.txt for
901 detailed information for super image.
902 output_super_empty: If provided, copies a super_empty.img file from the
903 target files package to this path.
904 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700905 # Create super_empty.img using the merged misc_info.txt.
906
Daniel Norman4cc9df62019-07-18 10:11:07 -0700907 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700908
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900909 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
910 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700911
912 if use_dynamic_partitions != 'true' and output_super_empty:
913 raise ValueError(
914 'Building super_empty.img requires use_dynamic_partitions=true.')
915 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700916 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700917 build_super_image_args = [
918 misc_info_txt,
919 super_empty_img,
920 ]
921 build_super_image.main(build_super_image_args)
922
923 # Copy super_empty.img to the user-provided output_super_empty location.
924 if output_super_empty:
925 shutil.copyfile(super_empty_img, output_super_empty)
926
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700927
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900928def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700929 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900930
931 Args:
932 output_file: The name of the zip archive target files package.
933 source_dir: The target directory contains package to be archived.
934 temp_dir: Path to temporary directory for any intermediate files.
935 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800936 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900937 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700938 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800939
Daniel Normandbbf5a32020-10-22 16:03:32 -0700940 def files_from_path(target_path, extra_args=None):
941 """Gets files under the given path and return a sorted list."""
942 find_command = ['find', target_path] + (extra_args or [])
943 find_process = common.Run(
944 find_command, stdout=subprocess.PIPE, verbose=False)
945 return common.RunAndCheckOutput(['sort'],
946 stdin=find_process.stdout,
947 verbose=False)
948
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900949 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700950 other_content = files_from_path(
951 source_dir,
952 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800953
Tao Bao2ad4b822019-06-27 16:52:12 -0700954 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800955 f.write(meta_content)
956 f.write(other_content)
957
958 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800959 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800960 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700961 '-o',
962 output_zip,
963 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900964 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -0800965 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -0700966 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800967 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900968
969 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -0800970 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900971 logger.info('finished creating %s', output_file)
972
973 return output_zip
974
975
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900976def merge_target_files(temp_dir, framework_target_files, framework_item_list,
977 framework_misc_info_keys, vendor_target_files,
978 vendor_item_list, output_target_files, output_dir,
979 output_item_list, output_ota, output_img,
980 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700981 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900982
983 This function takes framework and vendor target files packages as input,
984 performs various file extractions, special case processing, and finally
985 creates a merged zip archive as output.
986
987 Args:
988 temp_dir: The name of a directory we use when we extract items from the
989 input target files packages, and also a scratch directory that we use for
990 temporary files.
991 framework_target_files: The name of the zip archive containing the framework
992 partial target files package.
993 framework_item_list: The list of items to extract from the partial framework
994 target files package as is, meaning these items will land in the output
995 target files package exactly as they appear in the input partial framework
996 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -0700997 framework_misc_info_keys: A list of keys to obtain from the framework
998 instance of META/misc_info.txt. The remaining keys should come from the
999 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001000 vendor_target_files: The name of the zip archive containing the vendor
1001 partial target files package.
1002 vendor_item_list: The list of items to extract from the partial vendor
1003 target files package as is, meaning these items will land in the output
1004 target files package exactly as they appear in the input partial vendor
1005 target files package.
1006 output_target_files: The name of the output zip archive target files package
1007 created by merging framework and vendor.
1008 output_dir: The destination directory for saving merged files.
1009 output_item_list: The list of items to copy into the output_dir.
1010 output_ota: The name of the output zip archive ota package.
1011 output_img: The name of the output zip archive img package.
1012 output_super_empty: If provided, creates a super_empty.img file from the
1013 merged target files package and saves it at this path.
1014 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1015 devices and write it to the system image.
1016 """
1017
1018 logger.info('starting: merge framework %s and vendor %s into output %s',
1019 framework_target_files, vendor_target_files, output_target_files)
1020
1021 output_target_files_temp_dir = create_merged_package(
1022 temp_dir, framework_target_files, framework_item_list,
1023 vendor_target_files, vendor_item_list, framework_misc_info_keys,
1024 rebuild_recovery)
1025
Yifan Hongade0d3f2019-08-21 16:37:11 -07001026 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001027 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001028
Daniel Norman21c34f72020-11-11 17:25:50 -08001029 partition_map = common.PartitionMapFromTargetFiles(
1030 output_target_files_temp_dir)
1031
Daniel Normand3351562020-10-29 12:33:11 -07001032 # Generate and check for cross-partition violations of sharedUserId
1033 # values in APKs. This requires the input target-files packages to contain
1034 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001035 shareduid_violation_modules = os.path.join(
1036 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1037 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001038 violation = find_shareduid_violation.FindShareduidViolation(
1039 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001040
1041 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001042 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001043
1044 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001045 framework_partitions = item_list_to_partition_set(framework_item_list)
1046 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001047 shareduid_errors = common.SharedUidPartitionViolations(
1048 json.loads(violation), [framework_partitions, vendor_partitions])
1049 if shareduid_errors:
1050 for error in shareduid_errors:
1051 logger.error(error)
1052 raise ValueError('sharedUserId APK error. See %s' %
1053 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001054
Daniel Norman48603ff2021-02-22 15:15:24 -08001055 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001056 filtered_partitions = {
1057 partition: path
1058 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001059 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1060 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001061
1062 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001063 common.RunHostInitVerifier(
1064 product_out=output_target_files_temp_dir,
1065 partition_map=filtered_partitions)
1066
Daniel Norman48603ff2021-02-22 15:15:24 -08001067 # Check that the split sepolicy from the multiple builds can compile.
1068 split_sepolicy_cmd = compile_split_sepolicy(
1069 product_out=output_target_files_temp_dir,
1070 partition_map=filtered_partitions,
1071 output_policy=os.path.join(output_target_files_temp_dir,
1072 'META/combined.policy'))
1073 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1074 common.RunAndCheckOutput(split_sepolicy_cmd)
1075 # TODO(b/178864050): Run tests on the combined.policy file.
1076
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001077 generate_images(output_target_files_temp_dir, rebuild_recovery)
1078
1079 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1080
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001081 # Finally, create the output target files zip archive and/or copy the
1082 # output items to the output target files directory.
1083
1084 if output_dir:
1085 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1086
1087 if not output_target_files:
1088 return
1089
1090 output_zip = create_target_files_archive(output_target_files,
1091 output_target_files_temp_dir,
1092 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001093
Daniel Norman74eb74b2019-09-18 14:01:48 -07001094 # Create the IMG package from the merged target files package.
1095
1096 if output_img:
1097 img_from_target_files.main([output_zip, output_img])
1098
Daniel Norman3b64ce12019-04-16 16:11:35 -07001099 # Create the OTA package from the merged target files package.
1100
1101 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001102 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001103
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001104
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001105def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001106 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001107
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001108 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001109 directory. It also cleans up the temporary directory.
1110
1111 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001112 func: The function to call. Should accept one parameter, the path to the
1113 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001114 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001115 """
1116
1117 # Create a temporary directory. This will serve as the parent of directories
1118 # we use when we extract items from the input target files packages, and also
1119 # a scratch directory that we use for temporary files.
1120
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001121 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1122
1123 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001124 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001125 finally:
1126 if keep_tmp:
1127 logger.info('keeping %s', temp_dir)
1128 else:
1129 common.Cleanup()
1130
1131
1132def main():
1133 """The main function.
1134
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001135 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001136 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001137 """
1138
1139 common.InitLogging()
1140
Bill Peckhamf753e152019-02-19 18:02:46 -08001141 def option_handler(o, a):
1142 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001143 logger.warning(
1144 '--system-target-files has been renamed to --framework-target-files')
1145 OPTIONS.framework_target_files = a
1146 elif o == '--framework-target-files':
1147 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001148 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001149 logger.warning(
1150 '--system-item-list has been renamed to --framework-item-list')
1151 OPTIONS.framework_item_list = a
1152 elif o == '--framework-item-list':
1153 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001154 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001155 logger.warning('--system-misc-info-keys has been renamed to '
1156 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001157 OPTIONS.framework_misc_info_keys = a
1158 elif o == '--framework-misc-info-keys':
1159 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001160 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001161 logger.warning(
1162 '--other-target-files has been renamed to --vendor-target-files')
1163 OPTIONS.vendor_target_files = a
1164 elif o == '--vendor-target-files':
1165 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001166 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001167 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001168 OPTIONS.vendor_item_list = a
1169 elif o == '--vendor-item-list':
1170 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001171 elif o == '--output-target-files':
1172 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001173 elif o == '--output-dir':
1174 OPTIONS.output_dir = a
1175 elif o == '--output-item-list':
1176 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001177 elif o == '--output-ota':
1178 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001179 elif o == '--output-img':
1180 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001181 elif o == '--output-super-empty':
1182 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001183 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001184 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001185 elif o == '--allow-duplicate-apkapex-keys':
1186 OPTIONS.allow_duplicate_apkapex_keys = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001187 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001188 OPTIONS.keep_tmp = True
1189 else:
1190 return False
1191 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001192
Bill Peckhamf753e152019-02-19 18:02:46 -08001193 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001194 sys.argv[1:],
1195 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001196 extra_long_opts=[
1197 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001198 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001199 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001200 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001201 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001202 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001203 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001204 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001205 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001206 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001207 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001208 'output-dir=',
1209 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001210 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001211 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001212 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001213 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001214 'allow-duplicate-apkapex-keys',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001215 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001216 ],
1217 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001218
Tao Bao2ad4b822019-06-27 16:52:12 -07001219 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001220 if (args or OPTIONS.framework_target_files is None or
1221 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001222 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001223 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001224 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001225 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001226
Daniel Normand5d70ea2019-06-05 15:13:43 -07001227 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001228 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001229 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001230 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001231
Daniel Normand5d70ea2019-06-05 15:13:43 -07001232 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001233 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001234 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001235 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001236 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001237
Daniel Normand5d70ea2019-06-05 15:13:43 -07001238 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001239 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001240 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001241 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001242
Daniel Normanfdb38812019-04-15 09:47:24 -07001243 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001244 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001245 else:
1246 output_item_list = None
1247
Daniel Normane5964522019-03-19 10:32:03 -07001248 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001249 framework_item_list=framework_item_list,
1250 framework_misc_info_keys=framework_misc_info_keys,
1251 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001252 sys.exit(1)
1253
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001254 call_func_with_temp_dir(
1255 lambda temp_dir: merge_target_files(
1256 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001257 framework_target_files=OPTIONS.framework_target_files,
1258 framework_item_list=framework_item_list,
1259 framework_misc_info_keys=framework_misc_info_keys,
1260 vendor_target_files=OPTIONS.vendor_target_files,
1261 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001262 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001263 output_dir=OPTIONS.output_dir,
1264 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001265 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001266 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001267 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001268 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001269
1270
1271if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001272 main()