blob: 5e6c42d84e1a1a523b184146b3bd255e2a510473 [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 Normane9af70a2021-04-15 16:39:22 -070099import apex_utils
Daniel Normandb8cacc2021-04-09 15:34:43 -0700100import build_image
Daniel Normanf0318252019-04-15 11:34:56 -0700101import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -0700102import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -0700103import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700104import img_from_target_files
Daniel Normanb8d52a22020-10-26 17:55:00 -0700105import find_shareduid_violation
Daniel Norman3b64ce12019-04-16 16:11:35 -0700106import ota_from_target_files
Daniel Normandb8cacc2021-04-09 15:34:43 -0700107import sparse_img
108import verity_utils
109
110from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800111
112logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -0700113
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800114OPTIONS = common.OPTIONS
Bill Peckhamcb848172020-04-03 12:50:47 -0700115# Always turn on verbose logging.
116OPTIONS.verbose = True
Daniel Normand5d70ea2019-06-05 15:13:43 -0700117OPTIONS.framework_target_files = None
118OPTIONS.framework_item_list = None
119OPTIONS.framework_misc_info_keys = None
120OPTIONS.vendor_target_files = None
121OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800122OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700123OPTIONS.output_dir = None
124OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700125OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700126OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700127OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700128# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700129OPTIONS.rebuild_recovery = False
Daniel Normanb0c75912020-09-24 14:30:21 -0700130# TODO(b/150582573): Remove this option.
131OPTIONS.allow_duplicate_apkapex_keys = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800132OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800133
Bill Peckham19c3feb2020-03-20 18:31:43 -0700134# In an item list (framework or vendor), we may see entries that select whole
135# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the
136# system partition). The following regex matches this and extracts the
137# partition name.
138
139PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$')
140
Bill Peckham5c7b0342020-04-03 15:36:23 -0700141# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
142# the file. We use these partition tags to filter the entries in those files
143# from the two different target files packages to produce a merged apexkeys.txt
144# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
145# like this: 'partition="product"'. We use the group syntax grab the value of
146# the tag. We use non-greedy matching in case there are other fields on the
147# same line.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700148
Bill Peckham5c7b0342020-04-03 15:36:23 -0700149PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700150
151# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
152# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
153
154MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
155
Daniel Normand5d70ea2019-06-05 15:13:43 -0700156# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
157# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800158# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700159# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800160
Daniel Normand5d70ea2019-06-05 15:13:43 -0700161DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800162 'META/apkcerts.txt',
163 'META/filesystem_config.txt',
164 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800165 'META/update_engine_config.txt',
166 'PRODUCT/*',
167 'ROOT/*',
168 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700169)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800170
Daniel Normand5d70ea2019-06-05 15:13:43 -0700171# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700172# framework instance of META/misc_info.txt. The remaining keys should come
173# from the vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800174
Daniel Normand5d70ea2019-06-05 15:13:43 -0700175DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800176 'avb_system_hashtree_enable',
177 'avb_system_add_hashtree_footer_args',
178 'avb_system_key_path',
179 'avb_system_algorithm',
180 'avb_system_rollback_index_location',
181 'avb_product_hashtree_enable',
182 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900183 'avb_system_ext_hashtree_enable',
184 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800185 'system_root_image',
186 'root_dir',
187 'ab_update',
188 'default_system_dev_certificate',
189 'system_size',
Chris Gross203191b2020-05-30 02:39:12 +0000190 'building_system_image',
191 'building_system_ext_image',
192 'building_product_image',
Daniel Normanedf12472019-05-22 10:47:08 -0700193)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800194
Daniel Normand5d70ea2019-06-05 15:13:43 -0700195# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
196# vendor target files package as is, meaning these items will land in the output
197# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800198# files package.
199
Daniel Normand5d70ea2019-06-05 15:13:43 -0700200DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800201 'META/boot_filesystem_config.txt',
202 'META/otakeys.txt',
203 'META/releasetools.py',
204 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800205 'BOOT/*',
206 'DATA/*',
207 'ODM/*',
208 'OTA/android-info.txt',
209 'PREBUILT_IMAGES/*',
210 'RADIO/*',
211 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700212)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800213
Daniel Normanedf12472019-05-22 10:47:08 -0700214# The merge config lists should not attempt to extract items from both
215# builds for any of the following partitions. The partitions in
216# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700217# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700218
219SINGLE_BUILD_PARTITIONS = (
220 'BOOT/',
221 'DATA/',
222 'ODM/',
223 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900224 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700225 'RADIO/',
226 'RECOVERY/',
227 'ROOT/',
228 'SYSTEM/',
229 'SYSTEM_OTHER/',
230 'VENDOR/',
Yifan Hongcfb917a2020-05-07 14:58:20 -0700231 'VENDOR_DLKM/',
Yifan Hongf496f1b2020-07-15 16:52:59 -0700232 'ODM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700233)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800234
235
Chris Grossfabf50a2019-05-02 12:42:09 -0700236def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700237 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700238
Tao Bao2ad4b822019-06-27 16:52:12 -0700239 This function sorts the contents of the list or dict and then writes the
240 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700241
242 Args:
243 data: The list or dict to sort and write.
244 path: Path to the file to write the sorted values to. The file at path will
245 be overridden if it exists.
246 """
247 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700248 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700249 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
250 data, dict) else '{}\n'.format(entry)
251 output.write(out_str)
252
253
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800254def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700255 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800256
257 This function extracts from the specified target files zip archive into the
258 specified temporary directory, the items specified in the extract item list.
259
260 Args:
261 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800262 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700263 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800264 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800265 """
266
267 logger.info('extracting from %s', target_files)
268
269 # Filter the extract_item_list to remove any items that do not exist in the
270 # zip file. Otherwise, the extraction step will fail.
271
Daniel Norman4cc9df62019-07-18 10:11:07 -0700272 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800273 target_files_namelist = target_files_zipfile.namelist()
274
275 filtered_extract_item_list = []
276 for pattern in extract_item_list:
277 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
278 if not matching_namelist:
279 logger.warning('no match for %s', pattern)
280 else:
281 filtered_extract_item_list.append(pattern)
282
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800283 # Extract from target_files into target_files_temp_dir the
284 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800285
Daniel Normane5b134a2019-04-17 14:54:06 -0700286 common.UnzipToDir(target_files, target_files_temp_dir,
287 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800288
289
Daniel Normanfdb38812019-04-15 09:47:24 -0700290def copy_items(from_dir, to_dir, patterns):
291 """Similar to extract_items() except uses an input dir instead of zip."""
292 file_paths = []
293 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700294 file_paths.extend(
295 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
296 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700297
298 filtered_file_paths = set()
299 for pattern in patterns:
300 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
301
302 for file_path in filtered_file_paths:
303 original_file_path = os.path.join(from_dir, file_path)
304 copied_file_path = os.path.join(to_dir, file_path)
305 copied_file_dir = os.path.dirname(copied_file_path)
306 if not os.path.exists(copied_file_dir):
307 os.makedirs(copied_file_dir)
308 if os.path.islink(original_file_path):
309 os.symlink(os.readlink(original_file_path), copied_file_path)
310 else:
311 shutil.copyfile(original_file_path, copied_file_path)
312
313
Daniel Normand5d70ea2019-06-05 15:13:43 -0700314def validate_config_lists(framework_item_list, framework_misc_info_keys,
315 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700316 """Performs validations on the merge config lists.
317
318 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700319 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700320 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700321 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700322 instance of META/misc_info.txt. The remaining keys should come from the
323 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700324 vendor_item_list: The list of items to extract from the partial vendor
325 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700326
327 Returns:
328 False if a validation fails, otherwise true.
329 """
Daniel Normanedf12472019-05-22 10:47:08 -0700330 has_error = False
331
Daniel Normand5d70ea2019-06-05 15:13:43 -0700332 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
333 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700334
Daniel Normand5d70ea2019-06-05 15:13:43 -0700335 combined_item_set = set(framework_item_list)
336 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700337
338 # Check that the merge config lists are not missing any item specified
339 # by the default config lists.
340 difference = default_combined_item_set.difference(combined_item_set)
341 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700342 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700343 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700344 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700345 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700346 has_error = True
347
Daniel Normandbbf5a32020-10-22 16:03:32 -0700348 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700349 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700350 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
351 in_framework = (
352 any(item.startswith(partition) for item in framework_item_list) or
353 image_path in framework_item_list)
354 in_vendor = (
355 any(item.startswith(partition) for item in vendor_item_list) or
356 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700357 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700358 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700359 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900360 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700361 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700362 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700363
Daniel Normandb8cacc2021-04-09 15:34:43 -0700364 if ('dynamic_partition_list'
365 in framework_misc_info_keys) or ('super_partition_groups'
366 in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700367 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700368 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700369 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700370
Daniel Normanedf12472019-05-22 10:47:08 -0700371 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700372
373
Daniel Normand5d70ea2019-06-05 15:13:43 -0700374def process_ab_partitions_txt(framework_target_files_temp_dir,
375 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700376 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700377 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800378
Tao Bao2ad4b822019-06-27 16:52:12 -0700379 This function merges the contents of the META/ab_partitions.txt files from the
380 framework directory and the vendor directory, placing the merged result in the
381 output directory. The precondition in that the files are already extracted.
382 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700383 merged content. The format for each ab_partitions.txt is one partition name
384 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800385
386 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700387 framework_target_files_temp_dir: The name of a directory containing the
388 special items extracted from the framework target files package.
389 vendor_target_files_temp_dir: The name of a directory containing the special
390 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700391 output_target_files_temp_dir: The name of a directory that will be used to
392 create the output target files package after all the special cases are
393 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800394 """
395
Daniel Normand5d70ea2019-06-05 15:13:43 -0700396 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
397 'META', 'ab_partitions.txt')
398
399 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700400 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800401
Daniel Normand5d70ea2019-06-05 15:13:43 -0700402 with open(framework_ab_partitions_txt) as f:
403 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800404
Daniel Normand5d70ea2019-06-05 15:13:43 -0700405 with open(vendor_ab_partitions_txt) as f:
406 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800407
Daniel Normand5d70ea2019-06-05 15:13:43 -0700408 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800409
Daniel Normane5b134a2019-04-17 14:54:06 -0700410 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
411 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800412
Chris Grossfabf50a2019-05-02 12:42:09 -0700413 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800414
415
Daniel Normand5d70ea2019-06-05 15:13:43 -0700416def process_misc_info_txt(framework_target_files_temp_dir,
417 vendor_target_files_temp_dir,
418 output_target_files_temp_dir,
419 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700420 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800421
422 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700423 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800424 output directory. The precondition in that the files are already extracted.
425 The post condition is that the output META/misc_info.txt contains the merged
426 content.
427
428 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700429 framework_target_files_temp_dir: The name of a directory containing the
430 special items extracted from the framework target files package.
431 vendor_target_files_temp_dir: The name of a directory containing the special
432 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700433 output_target_files_temp_dir: The name of a directory that will be used to
434 create the output target files package after all the special cases are
435 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700436 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700437 instance of META/misc_info.txt. The remaining keys should come from the
438 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800439 """
440
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900441 misc_info_path = ['META', 'misc_info.txt']
442 framework_dict = common.LoadDictionaryFromFile(
443 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800444
Daniel Normand5d70ea2019-06-05 15:13:43 -0700445 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800446
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900447 merged_dict = common.LoadDictionaryFromFile(
448 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800449
Daniel Normand5d70ea2019-06-05 15:13:43 -0700450 # Replace certain values in merged_dict with values from
451 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800452
Daniel Normand5d70ea2019-06-05 15:13:43 -0700453 for key in framework_misc_info_keys:
454 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800455
Daniel Norman19b9fe92019-03-19 14:48:02 -0700456 # Merge misc info keys used for Dynamic Partitions.
Daniel Normandb8cacc2021-04-09 15:34:43 -0700457 if (merged_dict.get('use_dynamic_partitions')
458 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700459 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800460 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700461 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700462 # Ensure that add_img_to_target_files rebuilds super split images for
463 # devices that retrofit dynamic partitions. This flag may have been set to
464 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700465 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700466
Daniel Norman38888d32020-11-19 14:51:15 -0800467 # If AVB is enabled then ensure that we build vbmeta.img.
468 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
469 # skip building an incomplete vbmeta.img.
470 if merged_dict.get('avb_enable') == 'true':
471 merged_dict['avb_building_vbmeta_image'] = 'true'
472
Daniel Normand5d70ea2019-06-05 15:13:43 -0700473 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700474 # depending on which dictionary the key came from.
475 # Only the file basename is required because all selinux_fc properties are
476 # replaced with the full path to the file under META/ when misc_info.txt is
477 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700478 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700479 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700480 merged_dict[key] = 'vendor_file_contexts.bin'
481 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700482 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700483 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700484
Daniel Normane5b134a2019-04-17 14:54:06 -0700485 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
486 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700487 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800488
489
Daniel Normand5d70ea2019-06-05 15:13:43 -0700490def process_dynamic_partitions_info_txt(framework_target_files_dir,
491 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700492 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700493 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700494
495 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700496 files from the framework directory and the vendor directory, placing the
497 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700498
Daniel Normand5d70ea2019-06-05 15:13:43 -0700499 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700500 directory does not exist.
501
502 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700503 framework_target_files_dir: The name of a directory containing the special
504 items extracted from the framework target files package.
505 vendor_target_files_dir: The name of a directory containing the special
506 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700507 output_target_files_dir: The name of a directory that will be used to create
508 the output target files package after all the special cases are processed.
509 """
510
511 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700512 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700513 'dynamic_partitions_info.txt')):
514 return
515
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900516 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700517
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900518 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
519 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
520 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
521 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700522
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700523 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700524 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800525 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700526
527 output_dynamic_partitions_info_txt = os.path.join(
528 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700529 write_sorted_data(
530 data=merged_dynamic_partitions_dict,
531 path=output_dynamic_partitions_info_txt)
532
533
Bill Peckham19c3feb2020-03-20 18:31:43 -0700534def item_list_to_partition_set(item_list):
535 """Converts a target files item list to a partition set.
536
537 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
538 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
539 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
540 contents of a partition of the same name. Other items in the list, such as the
541 'OTA' example contain metadata. This function iterates such a list, returning
542 a set that contains the partition entries.
543
544 Args:
545 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700546
Bill Peckham19c3feb2020-03-20 18:31:43 -0700547 Returns:
548 A set of partitions extracted from the list of items.
549 """
550
551 partition_set = set()
552
553 for item in item_list:
554 match = PARTITION_ITEM_PATTERN.search(item.strip())
555 partition_tag = match.group(1).lower() if match else None
556
557 if partition_tag:
558 partition_set.add(partition_tag)
559
560 return partition_set
561
562
Daniel Normand5d70ea2019-06-05 15:13:43 -0700563def process_apex_keys_apk_certs_common(framework_target_files_dir,
564 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700565 output_target_files_dir,
566 framework_partition_set,
567 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700568 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700569
570 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700571 META/apkcerts.txt files from the framework directory and the vendor directory,
572 placing the merged result in the output directory. The precondition in that
573 the files are already extracted. The post condition is that the output
574 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700575
576 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700577 framework_target_files_dir: The name of a directory containing the special
578 items extracted from the framework target files package.
579 vendor_target_files_dir: The name of a directory containing the special
580 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700581 output_target_files_dir: The name of a directory that will be used to create
582 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700583 framework_partition_set: Partitions that are considered framework
584 partitions. Used to filter apexkeys.txt and apkcerts.txt.
585 vendor_partition_set: Partitions that are considered vendor partitions. Used
586 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700587 file_name: The name of the file to merge. One of apkcerts.txt or
588 apexkeys.txt.
589 """
590
591 def read_helper(d):
592 temp = {}
593 file_path = os.path.join(d, 'META', file_name)
594 with open(file_path) as f:
595 for line in f:
596 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700597 name = line.split()[0]
598 match = MODULE_KEY_PATTERN.search(name)
599 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700600 return temp
601
Daniel Normand5d70ea2019-06-05 15:13:43 -0700602 framework_dict = read_helper(framework_target_files_dir)
603 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700604 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700605
Bill Peckham19c3feb2020-03-20 18:31:43 -0700606 def filter_into_merged_dict(item_dict, partition_set):
607 for key, value in item_dict.items():
608 match = PARTITION_TAG_PATTERN.search(value)
609
610 if match is None:
611 raise ValueError('Entry missing partition tag: %s' % value)
612
613 partition_tag = match.group(1)
614
615 if partition_tag in partition_set:
616 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700617 if OPTIONS.allow_duplicate_apkapex_keys:
618 # TODO(b/150582573) Always raise on duplicates.
619 logger.warning('Duplicate key %s' % key)
620 continue
621 else:
622 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700623
624 merged_dict[key] = value
625
626 filter_into_merged_dict(framework_dict, framework_partition_set)
627 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700628
629 output_file = os.path.join(output_target_files_dir, 'META', file_name)
630
Bill Peckham19c3feb2020-03-20 18:31:43 -0700631 # The following code is similar to write_sorted_data, but different enough
632 # that we couldn't use that function. We need the output to be sorted by the
633 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
634 # allows the sort to be consistent with the framework/vendor input data and
635 # eases comparison of input data with merged data.
636 with open(output_file, 'w') as output:
637 for key in sorted(merged_dict.keys()):
638 out_str = merged_dict[key] + '\n'
639 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700640
641
Daniel Normand5d70ea2019-06-05 15:13:43 -0700642def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700643 output_target_files_dir):
644 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700645 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
646 'framework_file_contexts.bin')
647 if not os.path.exists(framework_fc_path):
648 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
649 'file_contexts.bin')
650 if not os.path.exists(framework_fc_path):
651 raise ValueError('Missing framework file_contexts.bin.')
652 shutil.copyfile(
653 framework_fc_path,
654 os.path.join(output_target_files_dir, 'META',
655 'framework_file_contexts.bin'))
656
657 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
658 'vendor_file_contexts.bin')
659 if not os.path.exists(vendor_fc_path):
660 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700661 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700662 if not os.path.exists(vendor_fc_path):
663 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700664 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700665 vendor_fc_path,
666 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700667
668
Daniel Norman48603ff2021-02-22 15:15:24 -0800669def compile_split_sepolicy(product_out, partition_map, output_policy):
670 """Uses secilc to compile a split sepolicy file.
671
672 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
673
674 Args:
675 product_out: PRODUCT_OUT directory, containing partition directories.
676 partition_map: A map of partition name -> relative path within product_out.
677 output_policy: The name of the output policy created by secilc.
678
679 Returns:
680 A command list that can be executed to create the compiled sepolicy.
681 """
682
683 def get_file(partition, path):
684 if partition not in partition_map:
685 logger.warning('Cannot load SEPolicy files for missing partition %s',
686 partition)
687 return None
688 return os.path.join(product_out, partition_map[partition], path)
689
690 # Load the kernel sepolicy version from the FCM. This is normally provided
691 # directly to selinux.cpp as a build flag, but is also available in this file.
692 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
693 if not fcm_file or not os.path.exists(fcm_file):
694 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
695 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
696 'sepolicy/kernel-sepolicy-version').text
697
698 # Load the vendor's plat sepolicy version. This is the version used for
699 # locating sepolicy mapping files.
700 vendor_plat_version_file = get_file('vendor',
701 'etc/selinux/plat_sepolicy_vers.txt')
702 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000703 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800704 raise ExternalError('Missing required sepolicy file %s',
705 vendor_plat_version_file)
706 with open(vendor_plat_version_file) as f:
707 vendor_plat_version = f.read().strip()
708
709 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
710 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
711 cmd.extend(['-c', kernel_sepolicy_version])
712 cmd.extend(['-o', output_policy])
713 cmd.extend(['-f', '/dev/null'])
714
715 required_policy_files = (
716 ('system', 'etc/selinux/plat_sepolicy.cil'),
717 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
718 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
719 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
720 )
721 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
722 required_policy_files)):
723 if not policy or not os.path.exists(policy):
724 raise ExternalError('Missing required sepolicy file %s', policy)
725 cmd.append(policy)
726
727 optional_policy_files = (
728 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
729 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
730 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
731 ('product', 'etc/selinux/product_sepolicy.cil'),
732 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
733 ('odm', 'etc/selinux/odm_sepolicy.cil'),
734 )
735 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
736 optional_policy_files)):
737 if policy and os.path.exists(policy):
738 cmd.append(policy)
739
740 return cmd
741
742
Daniel Normane9af70a2021-04-15 16:39:22 -0700743def validate_merged_apex_info(output_target_files_dir, partitions):
744 """Validates the APEX files in the merged target files directory.
745
746 Checks the APEX files in all possible preinstalled APEX directories.
747 Depends on the <partition>/apex/* APEX files within partitions.
748
749 Args:
750 output_target_files_dir: Output directory containing merged partition directories.
751 partitions: A list of all the partitions in the output directory.
752
753 Raises:
754 RuntimeError: if apex_utils fails to parse any APEX file.
755 ExternalError: if the same APEX package is provided by multiple partitions.
756 """
757 apex_packages = set()
758
759 apex_partitions = ('system', 'system_ext', 'product', 'vendor')
760 for partition in filter(lambda p: p in apex_partitions, partitions):
761 apex_info = apex_utils.GetApexInfoFromTargetFiles(
762 output_target_files_dir, partition, compressed_only=False)
763 partition_apex_packages = set([info.package_name for info in apex_info])
764 duplicates = apex_packages.intersection(partition_apex_packages)
765 if duplicates:
766 raise ExternalError(
767 'Duplicate APEX packages found in multiple partitions: %s' %
768 ' '.join(duplicates))
769 apex_packages.update(partition_apex_packages)
770
771
Daniel Normandb8cacc2021-04-09 15:34:43 -0700772def generate_care_map(partitions, output_target_files_dir):
773 """Generates a merged META/care_map.pb file in the output target files dir.
774
775 Depends on the info dict from META/misc_info.txt, as well as built images
776 within IMAGES/.
777
778 Args:
779 partitions: A list of partitions to potentially include in the care map.
780 output_target_files_dir: The name of a directory that will be used to create
781 the output target files package after all the special cases are processed.
782 """
783 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir)
784 partition_image_map = {}
785 for partition in partitions:
786 image_path = os.path.join(output_target_files_dir, 'IMAGES',
787 '{}.img'.format(partition))
788 if os.path.exists(image_path):
789 partition_image_map[partition] = image_path
790 # Regenerated images should have their image_size property already set.
791 image_size_prop = '{}_image_size'.format(partition)
792 if image_size_prop not in OPTIONS.info_dict:
793 # Images copied directly from input target files packages will need
794 # their image sizes calculated.
795 partition_size = sparse_img.GetImagePartitionSize(image_path)
796 image_props = build_image.ImagePropFromGlobalDict(
797 OPTIONS.info_dict, partition)
798 verity_image_builder = verity_utils.CreateVerityImageBuilder(
799 image_props)
800 image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
801 OPTIONS.info_dict[image_size_prop] = image_size
802
803 AddCareMapForAbOta(
804 os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
805 PARTITIONS_WITH_CARE_MAP, partition_image_map)
806
807
Daniel Normand5d70ea2019-06-05 15:13:43 -0700808def process_special_cases(framework_target_files_temp_dir,
809 vendor_target_files_temp_dir,
810 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700811 framework_misc_info_keys, framework_partition_set,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700812 vendor_partition_set):
Tao Bao2ad4b822019-06-27 16:52:12 -0700813 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800814
815 Certain files in the output target files package require special-case
816 processing. This function performs all that special-case processing.
817
818 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700819 framework_target_files_temp_dir: The name of a directory containing the
820 special items extracted from the framework target files package.
821 vendor_target_files_temp_dir: The name of a directory containing the special
822 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700823 output_target_files_temp_dir: The name of a directory that will be used to
824 create the output target files package after all the special cases are
825 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700826 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700827 instance of META/misc_info.txt. The remaining keys should come from the
828 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700829 framework_partition_set: Partitions that are considered framework
830 partitions. Used to filter apexkeys.txt and apkcerts.txt.
831 vendor_partition_set: Partitions that are considered vendor partitions. Used
832 to filter apexkeys.txt and apkcerts.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800833 """
834
Daniel Normand5d70ea2019-06-05 15:13:43 -0700835 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700836 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700837 framework_target_files_temp_dir=framework_target_files_temp_dir,
838 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700839 output_target_files_temp_dir=output_target_files_temp_dir)
840
Daniel Norman72c626f2019-05-13 15:58:14 -0700841 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700842 framework_target_files_dir=framework_target_files_temp_dir,
843 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700844 output_target_files_dir=output_target_files_temp_dir)
845
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800846 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700847 framework_target_files_temp_dir=framework_target_files_temp_dir,
848 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800849 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700850 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800851
Daniel Normana61cde02019-05-03 14:19:13 -0700852 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700853 framework_target_files_dir=framework_target_files_temp_dir,
854 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700855 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700856
Chris Grossfabf50a2019-05-02 12:42:09 -0700857 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700858 framework_target_files_dir=framework_target_files_temp_dir,
859 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700860 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700861 framework_partition_set=framework_partition_set,
862 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700863 file_name='apkcerts.txt')
864
865 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700866 framework_target_files_dir=framework_target_files_temp_dir,
867 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700868 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700869 framework_partition_set=framework_partition_set,
870 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700871 file_name='apexkeys.txt')
872
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800873
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900874def create_merged_package(temp_dir, framework_target_files, framework_item_list,
875 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700876 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700877 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800878
879 Args:
880 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700881 input target files packages, and also a scratch directory that we use for
882 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700883 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700884 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700885 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700886 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700887 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700888 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700889 vendor_target_files: The name of the zip archive containing the vendor
890 partial target files package.
891 vendor_item_list: The list of items to extract from the partial vendor
892 target files package as is, meaning these items will land in the output
893 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700894 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -0700895 framework_misc_info_keys: A list of keys to obtain from the framework
896 instance of META/misc_info.txt. The remaining keys should come from the
897 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700898 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700899 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800900
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900901 Returns:
902 Path to merged package under temp directory.
903 """
Daniel Normandbbf5a32020-10-22 16:03:32 -0700904 # Extract "as is" items from the input framework and vendor partial target
905 # files packages directly into the output temporary directory, since these items
906 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800907
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800908 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -0800909 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700910 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800911 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700912 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -0800913 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700914 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800915 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700916 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800917
Daniel Normandbbf5a32020-10-22 16:03:32 -0700918 # Perform special case processing on META/* items.
919 # After this function completes successfully, all the files we need to create
920 # the output target files package are in place.
921 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
922 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700923 extract_items(
924 target_files=framework_target_files,
925 target_files_temp_dir=framework_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700926 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800927 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700928 target_files=vendor_target_files,
929 target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700930 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800931 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700932 framework_target_files_temp_dir=framework_target_files_temp_dir,
933 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800934 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700935 framework_misc_info_keys=framework_misc_info_keys,
936 framework_partition_set=item_list_to_partition_set(framework_item_list),
937 vendor_partition_set=item_list_to_partition_set(vendor_item_list))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800938
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900939 return output_target_files_temp_dir
940
941
942def generate_images(target_files_dir, rebuild_recovery):
943 """Generate images from target files.
944
945 This function takes merged output temporary directory and create images
946 from it.
947
948 Args:
949 target_files_dir: Path to merged temp directory.
950 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
951 devices and write it to the system image.
952 """
953
954 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800955
Daniel Normandbbf5a32020-10-22 16:03:32 -0700956 add_img_args = [
957 '--verbose',
958 '--add_missing',
959 ]
Bill Peckhame868aec2019-09-17 17:06:47 -0700960 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700961 if rebuild_recovery:
962 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900963 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800964
965 add_img_to_target_files.main(add_img_args)
966
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900967
968def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700969 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900970
971 Args:
972 target_dir: Path to the target file package which contains misc_info.txt for
973 detailed information for super image.
974 output_super_empty: If provided, copies a super_empty.img file from the
975 target files package to this path.
976 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700977 # Create super_empty.img using the merged misc_info.txt.
978
Daniel Norman4cc9df62019-07-18 10:11:07 -0700979 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700980
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900981 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
982 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700983
984 if use_dynamic_partitions != 'true' and output_super_empty:
985 raise ValueError(
986 'Building super_empty.img requires use_dynamic_partitions=true.')
987 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700988 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700989 build_super_image_args = [
990 misc_info_txt,
991 super_empty_img,
992 ]
993 build_super_image.main(build_super_image_args)
994
995 # Copy super_empty.img to the user-provided output_super_empty location.
996 if output_super_empty:
997 shutil.copyfile(super_empty_img, output_super_empty)
998
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700999
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001000def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -07001001 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001002
1003 Args:
1004 output_file: The name of the zip archive target files package.
1005 source_dir: The target directory contains package to be archived.
1006 temp_dir: Path to temporary directory for any intermediate files.
1007 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001008 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001009 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001010 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001011
Daniel Normandbbf5a32020-10-22 16:03:32 -07001012 def files_from_path(target_path, extra_args=None):
1013 """Gets files under the given path and return a sorted list."""
1014 find_command = ['find', target_path] + (extra_args or [])
1015 find_process = common.Run(
1016 find_command, stdout=subprocess.PIPE, verbose=False)
1017 return common.RunAndCheckOutput(['sort'],
1018 stdin=find_process.stdout,
1019 verbose=False)
1020
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001021 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001022 other_content = files_from_path(
1023 source_dir,
1024 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001025
Tao Bao2ad4b822019-06-27 16:52:12 -07001026 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001027 f.write(meta_content)
1028 f.write(other_content)
1029
1030 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001031 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001032 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001033 '-o',
1034 output_zip,
1035 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001036 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001037 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001038 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001039 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001040
1041 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001042 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001043 logger.info('finished creating %s', output_file)
1044
1045 return output_zip
1046
1047
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001048def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1049 framework_misc_info_keys, vendor_target_files,
1050 vendor_item_list, output_target_files, output_dir,
1051 output_item_list, output_ota, output_img,
1052 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -07001053 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001054
1055 This function takes framework and vendor target files packages as input,
1056 performs various file extractions, special case processing, and finally
1057 creates a merged zip archive as output.
1058
1059 Args:
1060 temp_dir: The name of a directory we use when we extract items from the
1061 input target files packages, and also a scratch directory that we use for
1062 temporary files.
1063 framework_target_files: The name of the zip archive containing the framework
1064 partial target files package.
1065 framework_item_list: The list of items to extract from the partial framework
1066 target files package as is, meaning these items will land in the output
1067 target files package exactly as they appear in the input partial framework
1068 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001069 framework_misc_info_keys: A list of keys to obtain from the framework
1070 instance of META/misc_info.txt. The remaining keys should come from the
1071 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001072 vendor_target_files: The name of the zip archive containing the vendor
1073 partial target files package.
1074 vendor_item_list: The list of items to extract from the partial vendor
1075 target files package as is, meaning these items will land in the output
1076 target files package exactly as they appear in the input partial vendor
1077 target files package.
1078 output_target_files: The name of the output zip archive target files package
1079 created by merging framework and vendor.
1080 output_dir: The destination directory for saving merged files.
1081 output_item_list: The list of items to copy into the output_dir.
1082 output_ota: The name of the output zip archive ota package.
1083 output_img: The name of the output zip archive img package.
1084 output_super_empty: If provided, creates a super_empty.img file from the
1085 merged target files package and saves it at this path.
1086 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1087 devices and write it to the system image.
1088 """
1089
1090 logger.info('starting: merge framework %s and vendor %s into output %s',
1091 framework_target_files, vendor_target_files, output_target_files)
1092
1093 output_target_files_temp_dir = create_merged_package(
1094 temp_dir, framework_target_files, framework_item_list,
1095 vendor_target_files, vendor_item_list, framework_misc_info_keys,
1096 rebuild_recovery)
1097
Yifan Hongade0d3f2019-08-21 16:37:11 -07001098 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001099 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001100
Daniel Norman21c34f72020-11-11 17:25:50 -08001101 partition_map = common.PartitionMapFromTargetFiles(
1102 output_target_files_temp_dir)
1103
Daniel Normand3351562020-10-29 12:33:11 -07001104 # Generate and check for cross-partition violations of sharedUserId
1105 # values in APKs. This requires the input target-files packages to contain
1106 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001107 shareduid_violation_modules = os.path.join(
1108 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1109 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001110 violation = find_shareduid_violation.FindShareduidViolation(
1111 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001112
1113 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001114 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001115
1116 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001117 framework_partitions = item_list_to_partition_set(framework_item_list)
1118 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001119 shareduid_errors = common.SharedUidPartitionViolations(
1120 json.loads(violation), [framework_partitions, vendor_partitions])
1121 if shareduid_errors:
1122 for error in shareduid_errors:
1123 logger.error(error)
1124 raise ValueError('sharedUserId APK error. See %s' %
1125 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001126
Daniel Norman48603ff2021-02-22 15:15:24 -08001127 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001128 filtered_partitions = {
1129 partition: path
1130 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001131 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1132 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001133
1134 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001135 common.RunHostInitVerifier(
1136 product_out=output_target_files_temp_dir,
1137 partition_map=filtered_partitions)
1138
Daniel Norman48603ff2021-02-22 15:15:24 -08001139 # Check that the split sepolicy from the multiple builds can compile.
1140 split_sepolicy_cmd = compile_split_sepolicy(
1141 product_out=output_target_files_temp_dir,
1142 partition_map=filtered_partitions,
1143 output_policy=os.path.join(output_target_files_temp_dir,
1144 'META/combined.policy'))
1145 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1146 common.RunAndCheckOutput(split_sepolicy_cmd)
1147 # TODO(b/178864050): Run tests on the combined.policy file.
1148
Daniel Normane9af70a2021-04-15 16:39:22 -07001149 # Run validation checks on the pre-installed APEX files.
1150 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
1151
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001152 generate_images(output_target_files_temp_dir, rebuild_recovery)
1153
1154 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1155
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001156 # Finally, create the output target files zip archive and/or copy the
1157 # output items to the output target files directory.
1158
1159 if output_dir:
1160 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1161
1162 if not output_target_files:
1163 return
1164
Daniel Normandb8cacc2021-04-09 15:34:43 -07001165 # Create the merged META/care_map.bp
1166 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
1167
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001168 output_zip = create_target_files_archive(output_target_files,
1169 output_target_files_temp_dir,
1170 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001171
Daniel Norman74eb74b2019-09-18 14:01:48 -07001172 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001173 if output_img:
1174 img_from_target_files.main([output_zip, output_img])
1175
Daniel Norman3b64ce12019-04-16 16:11:35 -07001176 # Create the OTA package from the merged target files package.
1177
1178 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001179 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001180
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001181
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001182def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001183 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001184
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001185 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001186 directory. It also cleans up the temporary directory.
1187
1188 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001189 func: The function to call. Should accept one parameter, the path to the
1190 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001191 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001192 """
1193
1194 # Create a temporary directory. This will serve as the parent of directories
1195 # we use when we extract items from the input target files packages, and also
1196 # a scratch directory that we use for temporary files.
1197
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001198 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1199
1200 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001201 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001202 finally:
1203 if keep_tmp:
1204 logger.info('keeping %s', temp_dir)
1205 else:
1206 common.Cleanup()
1207
1208
1209def main():
1210 """The main function.
1211
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001212 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001213 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001214 """
1215
1216 common.InitLogging()
1217
Bill Peckhamf753e152019-02-19 18:02:46 -08001218 def option_handler(o, a):
1219 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001220 logger.warning(
1221 '--system-target-files has been renamed to --framework-target-files')
1222 OPTIONS.framework_target_files = a
1223 elif o == '--framework-target-files':
1224 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001225 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001226 logger.warning(
1227 '--system-item-list has been renamed to --framework-item-list')
1228 OPTIONS.framework_item_list = a
1229 elif o == '--framework-item-list':
1230 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001231 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001232 logger.warning('--system-misc-info-keys has been renamed to '
1233 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001234 OPTIONS.framework_misc_info_keys = a
1235 elif o == '--framework-misc-info-keys':
1236 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001237 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001238 logger.warning(
1239 '--other-target-files has been renamed to --vendor-target-files')
1240 OPTIONS.vendor_target_files = a
1241 elif o == '--vendor-target-files':
1242 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001243 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001244 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001245 OPTIONS.vendor_item_list = a
1246 elif o == '--vendor-item-list':
1247 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001248 elif o == '--output-target-files':
1249 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001250 elif o == '--output-dir':
1251 OPTIONS.output_dir = a
1252 elif o == '--output-item-list':
1253 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001254 elif o == '--output-ota':
1255 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001256 elif o == '--output-img':
1257 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001258 elif o == '--output-super-empty':
1259 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001260 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001261 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001262 elif o == '--allow-duplicate-apkapex-keys':
1263 OPTIONS.allow_duplicate_apkapex_keys = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001264 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001265 OPTIONS.keep_tmp = True
1266 else:
1267 return False
1268 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001269
Bill Peckhamf753e152019-02-19 18:02:46 -08001270 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001271 sys.argv[1:],
1272 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001273 extra_long_opts=[
1274 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001275 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001276 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001277 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001278 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001279 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001280 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001281 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001282 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001283 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001284 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001285 'output-dir=',
1286 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001287 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001288 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001289 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001290 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001291 'allow-duplicate-apkapex-keys',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001292 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001293 ],
1294 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001295
Tao Bao2ad4b822019-06-27 16:52:12 -07001296 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001297 if (args or OPTIONS.framework_target_files is None or
1298 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001299 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001300 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001301 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001302 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001303
Daniel Normand5d70ea2019-06-05 15:13:43 -07001304 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001305 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001306 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001307 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001308
Daniel Normand5d70ea2019-06-05 15:13:43 -07001309 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001310 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001311 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001312 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001313 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001314
Daniel Normand5d70ea2019-06-05 15:13:43 -07001315 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001316 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001317 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001318 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001319
Daniel Normanfdb38812019-04-15 09:47:24 -07001320 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001321 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001322 else:
1323 output_item_list = None
1324
Daniel Normane5964522019-03-19 10:32:03 -07001325 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001326 framework_item_list=framework_item_list,
1327 framework_misc_info_keys=framework_misc_info_keys,
1328 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001329 sys.exit(1)
1330
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001331 call_func_with_temp_dir(
1332 lambda temp_dir: merge_target_files(
1333 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001334 framework_target_files=OPTIONS.framework_target_files,
1335 framework_item_list=framework_item_list,
1336 framework_misc_info_keys=framework_misc_info_keys,
1337 vendor_target_files=OPTIONS.vendor_target_files,
1338 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001339 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001340 output_dir=OPTIONS.output_dir,
1341 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001342 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001343 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001344 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001345 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001346
1347
1348if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001349 main()