blob: 17d30308875423e1d0a4d009822aeb7033b41407 [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 Normandb8cacc2021-04-09 15:34:43 -070099import build_image
Daniel Normanf0318252019-04-15 11:34:56 -0700100import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -0700101import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -0700102import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700103import img_from_target_files
Daniel Normanb8d52a22020-10-26 17:55:00 -0700104import find_shareduid_violation
Daniel Norman3b64ce12019-04-16 16:11:35 -0700105import ota_from_target_files
Daniel Normandb8cacc2021-04-09 15:34:43 -0700106import sparse_img
107import verity_utils
108
109from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800110
111logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -0700112
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800113OPTIONS = common.OPTIONS
Bill Peckhamcb848172020-04-03 12:50:47 -0700114# Always turn on verbose logging.
115OPTIONS.verbose = True
Daniel Normand5d70ea2019-06-05 15:13:43 -0700116OPTIONS.framework_target_files = None
117OPTIONS.framework_item_list = None
118OPTIONS.framework_misc_info_keys = None
119OPTIONS.vendor_target_files = None
120OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800121OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700122OPTIONS.output_dir = None
123OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700124OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700125OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700126OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700127# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700128OPTIONS.rebuild_recovery = False
Daniel Normanb0c75912020-09-24 14:30:21 -0700129# TODO(b/150582573): Remove this option.
130OPTIONS.allow_duplicate_apkapex_keys = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800131OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800132
Bill Peckham19c3feb2020-03-20 18:31:43 -0700133# In an item list (framework or vendor), we may see entries that select whole
134# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the
135# system partition). The following regex matches this and extracts the
136# partition name.
137
138PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$')
139
Bill Peckham5c7b0342020-04-03 15:36:23 -0700140# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
141# the file. We use these partition tags to filter the entries in those files
142# from the two different target files packages to produce a merged apexkeys.txt
143# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
144# like this: 'partition="product"'. We use the group syntax grab the value of
145# the tag. We use non-greedy matching in case there are other fields on the
146# same line.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700147
Bill Peckham5c7b0342020-04-03 15:36:23 -0700148PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700149
150# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
151# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
152
153MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
154
Daniel Normand5d70ea2019-06-05 15:13:43 -0700155# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
156# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800157# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700158# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800159
Daniel Normand5d70ea2019-06-05 15:13:43 -0700160DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800161 'META/apkcerts.txt',
162 'META/filesystem_config.txt',
163 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800164 'META/update_engine_config.txt',
165 'PRODUCT/*',
166 'ROOT/*',
167 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700168)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800169
Daniel Normand5d70ea2019-06-05 15:13:43 -0700170# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700171# framework instance of META/misc_info.txt. The remaining keys should come
172# from the vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800173
Daniel Normand5d70ea2019-06-05 15:13:43 -0700174DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800175 'avb_system_hashtree_enable',
176 'avb_system_add_hashtree_footer_args',
177 'avb_system_key_path',
178 'avb_system_algorithm',
179 'avb_system_rollback_index_location',
180 'avb_product_hashtree_enable',
181 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900182 'avb_system_ext_hashtree_enable',
183 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800184 'system_root_image',
185 'root_dir',
186 'ab_update',
187 'default_system_dev_certificate',
188 'system_size',
Chris Gross203191b2020-05-30 02:39:12 +0000189 'building_system_image',
190 'building_system_ext_image',
191 'building_product_image',
Daniel Normanedf12472019-05-22 10:47:08 -0700192)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800193
Daniel Normand5d70ea2019-06-05 15:13:43 -0700194# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
195# vendor target files package as is, meaning these items will land in the output
196# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800197# files package.
198
Daniel Normand5d70ea2019-06-05 15:13:43 -0700199DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800200 'META/boot_filesystem_config.txt',
201 'META/otakeys.txt',
202 'META/releasetools.py',
203 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800204 'BOOT/*',
205 'DATA/*',
206 'ODM/*',
207 'OTA/android-info.txt',
208 'PREBUILT_IMAGES/*',
209 'RADIO/*',
210 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700211)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800212
Daniel Normanedf12472019-05-22 10:47:08 -0700213# The merge config lists should not attempt to extract items from both
214# builds for any of the following partitions. The partitions in
215# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700216# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700217
218SINGLE_BUILD_PARTITIONS = (
219 'BOOT/',
220 'DATA/',
221 'ODM/',
222 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900223 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700224 'RADIO/',
225 'RECOVERY/',
226 'ROOT/',
227 'SYSTEM/',
228 'SYSTEM_OTHER/',
229 'VENDOR/',
Yifan Hongcfb917a2020-05-07 14:58:20 -0700230 'VENDOR_DLKM/',
Yifan Hongf496f1b2020-07-15 16:52:59 -0700231 'ODM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700232)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800233
234
Chris Grossfabf50a2019-05-02 12:42:09 -0700235def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700236 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700237
Tao Bao2ad4b822019-06-27 16:52:12 -0700238 This function sorts the contents of the list or dict and then writes the
239 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700240
241 Args:
242 data: The list or dict to sort and write.
243 path: Path to the file to write the sorted values to. The file at path will
244 be overridden if it exists.
245 """
246 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700247 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700248 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
249 data, dict) else '{}\n'.format(entry)
250 output.write(out_str)
251
252
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800253def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700254 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800255
256 This function extracts from the specified target files zip archive into the
257 specified temporary directory, the items specified in the extract item list.
258
259 Args:
260 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800261 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700262 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800263 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800264 """
265
266 logger.info('extracting from %s', target_files)
267
268 # Filter the extract_item_list to remove any items that do not exist in the
269 # zip file. Otherwise, the extraction step will fail.
270
Daniel Norman4cc9df62019-07-18 10:11:07 -0700271 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800272 target_files_namelist = target_files_zipfile.namelist()
273
274 filtered_extract_item_list = []
275 for pattern in extract_item_list:
276 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
277 if not matching_namelist:
278 logger.warning('no match for %s', pattern)
279 else:
280 filtered_extract_item_list.append(pattern)
281
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800282 # Extract from target_files into target_files_temp_dir the
283 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800284
Daniel Normane5b134a2019-04-17 14:54:06 -0700285 common.UnzipToDir(target_files, target_files_temp_dir,
286 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800287
288
Daniel Normanfdb38812019-04-15 09:47:24 -0700289def copy_items(from_dir, to_dir, patterns):
290 """Similar to extract_items() except uses an input dir instead of zip."""
291 file_paths = []
292 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700293 file_paths.extend(
294 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
295 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700296
297 filtered_file_paths = set()
298 for pattern in patterns:
299 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
300
301 for file_path in filtered_file_paths:
302 original_file_path = os.path.join(from_dir, file_path)
303 copied_file_path = os.path.join(to_dir, file_path)
304 copied_file_dir = os.path.dirname(copied_file_path)
305 if not os.path.exists(copied_file_dir):
306 os.makedirs(copied_file_dir)
307 if os.path.islink(original_file_path):
308 os.symlink(os.readlink(original_file_path), copied_file_path)
309 else:
310 shutil.copyfile(original_file_path, copied_file_path)
311
312
Daniel Normand5d70ea2019-06-05 15:13:43 -0700313def validate_config_lists(framework_item_list, framework_misc_info_keys,
314 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700315 """Performs validations on the merge config lists.
316
317 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700318 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700319 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700320 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700321 instance of META/misc_info.txt. The remaining keys should come from the
322 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700323 vendor_item_list: The list of items to extract from the partial vendor
324 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700325
326 Returns:
327 False if a validation fails, otherwise true.
328 """
Daniel Normanedf12472019-05-22 10:47:08 -0700329 has_error = False
330
Daniel Normand5d70ea2019-06-05 15:13:43 -0700331 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
332 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700333
Daniel Normand5d70ea2019-06-05 15:13:43 -0700334 combined_item_set = set(framework_item_list)
335 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700336
337 # Check that the merge config lists are not missing any item specified
338 # by the default config lists.
339 difference = default_combined_item_set.difference(combined_item_set)
340 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700341 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700342 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700343 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700344 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700345 has_error = True
346
Daniel Normandbbf5a32020-10-22 16:03:32 -0700347 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700348 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700349 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
350 in_framework = (
351 any(item.startswith(partition) for item in framework_item_list) or
352 image_path in framework_item_list)
353 in_vendor = (
354 any(item.startswith(partition) for item in vendor_item_list) or
355 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700356 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700357 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700358 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900359 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700360 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700361 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700362
Daniel Normandb8cacc2021-04-09 15:34:43 -0700363 if ('dynamic_partition_list'
364 in framework_misc_info_keys) or ('super_partition_groups'
365 in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700366 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700367 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700368 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700369
Daniel Normanedf12472019-05-22 10:47:08 -0700370 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700371
372
Daniel Normand5d70ea2019-06-05 15:13:43 -0700373def process_ab_partitions_txt(framework_target_files_temp_dir,
374 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700375 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700376 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800377
Tao Bao2ad4b822019-06-27 16:52:12 -0700378 This function merges the contents of the META/ab_partitions.txt files from the
379 framework directory and the vendor directory, placing the merged result in the
380 output directory. The precondition in that the files are already extracted.
381 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700382 merged content. The format for each ab_partitions.txt is one partition name
383 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800384
385 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700386 framework_target_files_temp_dir: The name of a directory containing the
387 special items extracted from the framework target files package.
388 vendor_target_files_temp_dir: The name of a directory containing the special
389 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700390 output_target_files_temp_dir: The name of a directory that will be used to
391 create the output target files package after all the special cases are
392 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800393 """
394
Daniel Normand5d70ea2019-06-05 15:13:43 -0700395 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
396 'META', 'ab_partitions.txt')
397
398 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700399 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800400
Daniel Normand5d70ea2019-06-05 15:13:43 -0700401 with open(framework_ab_partitions_txt) as f:
402 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800403
Daniel Normand5d70ea2019-06-05 15:13:43 -0700404 with open(vendor_ab_partitions_txt) as f:
405 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800406
Daniel Normand5d70ea2019-06-05 15:13:43 -0700407 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800408
Daniel Normane5b134a2019-04-17 14:54:06 -0700409 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
410 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800411
Chris Grossfabf50a2019-05-02 12:42:09 -0700412 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800413
414
Daniel Normand5d70ea2019-06-05 15:13:43 -0700415def process_misc_info_txt(framework_target_files_temp_dir,
416 vendor_target_files_temp_dir,
417 output_target_files_temp_dir,
418 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700419 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800420
421 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700422 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800423 output directory. The precondition in that the files are already extracted.
424 The post condition is that the output META/misc_info.txt contains the merged
425 content.
426
427 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700428 framework_target_files_temp_dir: The name of a directory containing the
429 special items extracted from the framework target files package.
430 vendor_target_files_temp_dir: The name of a directory containing the special
431 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700432 output_target_files_temp_dir: The name of a directory that will be used to
433 create the output target files package after all the special cases are
434 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700435 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700436 instance of META/misc_info.txt. The remaining keys should come from the
437 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800438 """
439
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900440 misc_info_path = ['META', 'misc_info.txt']
441 framework_dict = common.LoadDictionaryFromFile(
442 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800443
Daniel Normand5d70ea2019-06-05 15:13:43 -0700444 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800445
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900446 merged_dict = common.LoadDictionaryFromFile(
447 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800448
Daniel Normand5d70ea2019-06-05 15:13:43 -0700449 # Replace certain values in merged_dict with values from
450 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800451
Daniel Normand5d70ea2019-06-05 15:13:43 -0700452 for key in framework_misc_info_keys:
453 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800454
Daniel Norman19b9fe92019-03-19 14:48:02 -0700455 # Merge misc info keys used for Dynamic Partitions.
Daniel Normandb8cacc2021-04-09 15:34:43 -0700456 if (merged_dict.get('use_dynamic_partitions')
457 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700458 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800459 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700460 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700461 # Ensure that add_img_to_target_files rebuilds super split images for
462 # devices that retrofit dynamic partitions. This flag may have been set to
463 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700464 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700465
Daniel Norman38888d32020-11-19 14:51:15 -0800466 # If AVB is enabled then ensure that we build vbmeta.img.
467 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
468 # skip building an incomplete vbmeta.img.
469 if merged_dict.get('avb_enable') == 'true':
470 merged_dict['avb_building_vbmeta_image'] = 'true'
471
Daniel Normand5d70ea2019-06-05 15:13:43 -0700472 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700473 # depending on which dictionary the key came from.
474 # Only the file basename is required because all selinux_fc properties are
475 # replaced with the full path to the file under META/ when misc_info.txt is
476 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700477 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700478 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700479 merged_dict[key] = 'vendor_file_contexts.bin'
480 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700481 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700482 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700483
Daniel Normane5b134a2019-04-17 14:54:06 -0700484 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
485 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700486 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800487
488
Daniel Normand5d70ea2019-06-05 15:13:43 -0700489def process_dynamic_partitions_info_txt(framework_target_files_dir,
490 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700491 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700492 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700493
494 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700495 files from the framework directory and the vendor directory, placing the
496 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700497
Daniel Normand5d70ea2019-06-05 15:13:43 -0700498 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700499 directory does not exist.
500
501 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700502 framework_target_files_dir: The name of a directory containing the special
503 items extracted from the framework target files package.
504 vendor_target_files_dir: The name of a directory containing the special
505 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700506 output_target_files_dir: The name of a directory that will be used to create
507 the output target files package after all the special cases are processed.
508 """
509
510 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700511 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700512 'dynamic_partitions_info.txt')):
513 return
514
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900515 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700516
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900517 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
518 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
519 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
520 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700521
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700522 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700523 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800524 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700525
526 output_dynamic_partitions_info_txt = os.path.join(
527 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700528 write_sorted_data(
529 data=merged_dynamic_partitions_dict,
530 path=output_dynamic_partitions_info_txt)
531
532
Bill Peckham19c3feb2020-03-20 18:31:43 -0700533def item_list_to_partition_set(item_list):
534 """Converts a target files item list to a partition set.
535
536 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
537 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
538 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
539 contents of a partition of the same name. Other items in the list, such as the
540 'OTA' example contain metadata. This function iterates such a list, returning
541 a set that contains the partition entries.
542
543 Args:
544 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700545
Bill Peckham19c3feb2020-03-20 18:31:43 -0700546 Returns:
547 A set of partitions extracted from the list of items.
548 """
549
550 partition_set = set()
551
552 for item in item_list:
553 match = PARTITION_ITEM_PATTERN.search(item.strip())
554 partition_tag = match.group(1).lower() if match else None
555
556 if partition_tag:
557 partition_set.add(partition_tag)
558
559 return partition_set
560
561
Daniel Normand5d70ea2019-06-05 15:13:43 -0700562def process_apex_keys_apk_certs_common(framework_target_files_dir,
563 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700564 output_target_files_dir,
565 framework_partition_set,
566 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700567 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700568
569 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700570 META/apkcerts.txt files from the framework directory and the vendor directory,
571 placing the merged result in the output directory. The precondition in that
572 the files are already extracted. The post condition is that the output
573 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700574
575 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700576 framework_target_files_dir: The name of a directory containing the special
577 items extracted from the framework target files package.
578 vendor_target_files_dir: The name of a directory containing the special
579 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700580 output_target_files_dir: The name of a directory that will be used to create
581 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700582 framework_partition_set: Partitions that are considered framework
583 partitions. Used to filter apexkeys.txt and apkcerts.txt.
584 vendor_partition_set: Partitions that are considered vendor partitions. Used
585 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700586 file_name: The name of the file to merge. One of apkcerts.txt or
587 apexkeys.txt.
588 """
589
590 def read_helper(d):
591 temp = {}
592 file_path = os.path.join(d, 'META', file_name)
593 with open(file_path) as f:
594 for line in f:
595 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700596 name = line.split()[0]
597 match = MODULE_KEY_PATTERN.search(name)
598 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700599 return temp
600
Daniel Normand5d70ea2019-06-05 15:13:43 -0700601 framework_dict = read_helper(framework_target_files_dir)
602 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700603 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700604
Bill Peckham19c3feb2020-03-20 18:31:43 -0700605 def filter_into_merged_dict(item_dict, partition_set):
606 for key, value in item_dict.items():
607 match = PARTITION_TAG_PATTERN.search(value)
608
609 if match is None:
610 raise ValueError('Entry missing partition tag: %s' % value)
611
612 partition_tag = match.group(1)
613
614 if partition_tag in partition_set:
615 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700616 if OPTIONS.allow_duplicate_apkapex_keys:
617 # TODO(b/150582573) Always raise on duplicates.
618 logger.warning('Duplicate key %s' % key)
619 continue
620 else:
621 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700622
623 merged_dict[key] = value
624
625 filter_into_merged_dict(framework_dict, framework_partition_set)
626 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700627
628 output_file = os.path.join(output_target_files_dir, 'META', file_name)
629
Bill Peckham19c3feb2020-03-20 18:31:43 -0700630 # The following code is similar to write_sorted_data, but different enough
631 # that we couldn't use that function. We need the output to be sorted by the
632 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
633 # allows the sort to be consistent with the framework/vendor input data and
634 # eases comparison of input data with merged data.
635 with open(output_file, 'w') as output:
636 for key in sorted(merged_dict.keys()):
637 out_str = merged_dict[key] + '\n'
638 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700639
640
Daniel Normand5d70ea2019-06-05 15:13:43 -0700641def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700642 output_target_files_dir):
643 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700644 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
645 'framework_file_contexts.bin')
646 if not os.path.exists(framework_fc_path):
647 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
648 'file_contexts.bin')
649 if not os.path.exists(framework_fc_path):
650 raise ValueError('Missing framework file_contexts.bin.')
651 shutil.copyfile(
652 framework_fc_path,
653 os.path.join(output_target_files_dir, 'META',
654 'framework_file_contexts.bin'))
655
656 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
657 'vendor_file_contexts.bin')
658 if not os.path.exists(vendor_fc_path):
659 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700660 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700661 if not os.path.exists(vendor_fc_path):
662 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700663 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700664 vendor_fc_path,
665 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700666
667
Daniel Norman48603ff2021-02-22 15:15:24 -0800668def compile_split_sepolicy(product_out, partition_map, output_policy):
669 """Uses secilc to compile a split sepolicy file.
670
671 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
672
673 Args:
674 product_out: PRODUCT_OUT directory, containing partition directories.
675 partition_map: A map of partition name -> relative path within product_out.
676 output_policy: The name of the output policy created by secilc.
677
678 Returns:
679 A command list that can be executed to create the compiled sepolicy.
680 """
681
682 def get_file(partition, path):
683 if partition not in partition_map:
684 logger.warning('Cannot load SEPolicy files for missing partition %s',
685 partition)
686 return None
687 return os.path.join(product_out, partition_map[partition], path)
688
689 # Load the kernel sepolicy version from the FCM. This is normally provided
690 # directly to selinux.cpp as a build flag, but is also available in this file.
691 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
692 if not fcm_file or not os.path.exists(fcm_file):
693 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
694 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
695 'sepolicy/kernel-sepolicy-version').text
696
697 # Load the vendor's plat sepolicy version. This is the version used for
698 # locating sepolicy mapping files.
699 vendor_plat_version_file = get_file('vendor',
700 'etc/selinux/plat_sepolicy_vers.txt')
701 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000702 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800703 raise ExternalError('Missing required sepolicy file %s',
704 vendor_plat_version_file)
705 with open(vendor_plat_version_file) as f:
706 vendor_plat_version = f.read().strip()
707
708 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
709 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
710 cmd.extend(['-c', kernel_sepolicy_version])
711 cmd.extend(['-o', output_policy])
712 cmd.extend(['-f', '/dev/null'])
713
714 required_policy_files = (
715 ('system', 'etc/selinux/plat_sepolicy.cil'),
716 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
717 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
718 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
719 )
720 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
721 required_policy_files)):
722 if not policy or not os.path.exists(policy):
723 raise ExternalError('Missing required sepolicy file %s', policy)
724 cmd.append(policy)
725
726 optional_policy_files = (
727 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
728 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
729 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
730 ('product', 'etc/selinux/product_sepolicy.cil'),
731 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
732 ('odm', 'etc/selinux/odm_sepolicy.cil'),
733 )
734 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
735 optional_policy_files)):
736 if policy and os.path.exists(policy):
737 cmd.append(policy)
738
739 return cmd
740
741
Daniel Normandb8cacc2021-04-09 15:34:43 -0700742def generate_care_map(partitions, output_target_files_dir):
743 """Generates a merged META/care_map.pb file in the output target files dir.
744
745 Depends on the info dict from META/misc_info.txt, as well as built images
746 within IMAGES/.
747
748 Args:
749 partitions: A list of partitions to potentially include in the care map.
750 output_target_files_dir: The name of a directory that will be used to create
751 the output target files package after all the special cases are processed.
752 """
753 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir)
754 partition_image_map = {}
755 for partition in partitions:
756 image_path = os.path.join(output_target_files_dir, 'IMAGES',
757 '{}.img'.format(partition))
758 if os.path.exists(image_path):
759 partition_image_map[partition] = image_path
760 # Regenerated images should have their image_size property already set.
761 image_size_prop = '{}_image_size'.format(partition)
762 if image_size_prop not in OPTIONS.info_dict:
763 # Images copied directly from input target files packages will need
764 # their image sizes calculated.
765 partition_size = sparse_img.GetImagePartitionSize(image_path)
766 image_props = build_image.ImagePropFromGlobalDict(
767 OPTIONS.info_dict, partition)
768 verity_image_builder = verity_utils.CreateVerityImageBuilder(
769 image_props)
770 image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
771 OPTIONS.info_dict[image_size_prop] = image_size
772
773 AddCareMapForAbOta(
774 os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
775 PARTITIONS_WITH_CARE_MAP, partition_image_map)
776
777
Daniel Normand5d70ea2019-06-05 15:13:43 -0700778def process_special_cases(framework_target_files_temp_dir,
779 vendor_target_files_temp_dir,
780 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700781 framework_misc_info_keys, framework_partition_set,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700782 vendor_partition_set):
Tao Bao2ad4b822019-06-27 16:52:12 -0700783 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800784
785 Certain files in the output target files package require special-case
786 processing. This function performs all that special-case processing.
787
788 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700789 framework_target_files_temp_dir: The name of a directory containing the
790 special items extracted from the framework target files package.
791 vendor_target_files_temp_dir: The name of a directory containing the special
792 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700793 output_target_files_temp_dir: The name of a directory that will be used to
794 create the output target files package after all the special cases are
795 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700796 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700797 instance of META/misc_info.txt. The remaining keys should come from the
798 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700799 framework_partition_set: Partitions that are considered framework
800 partitions. Used to filter apexkeys.txt and apkcerts.txt.
801 vendor_partition_set: Partitions that are considered vendor partitions. Used
802 to filter apexkeys.txt and apkcerts.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800803 """
804
Daniel Normand5d70ea2019-06-05 15:13:43 -0700805 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700806 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700807 framework_target_files_temp_dir=framework_target_files_temp_dir,
808 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700809 output_target_files_temp_dir=output_target_files_temp_dir)
810
Daniel Norman72c626f2019-05-13 15:58:14 -0700811 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700812 framework_target_files_dir=framework_target_files_temp_dir,
813 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700814 output_target_files_dir=output_target_files_temp_dir)
815
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800816 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700817 framework_target_files_temp_dir=framework_target_files_temp_dir,
818 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800819 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700820 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800821
Daniel Normana61cde02019-05-03 14:19:13 -0700822 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700823 framework_target_files_dir=framework_target_files_temp_dir,
824 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700825 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700826
Chris Grossfabf50a2019-05-02 12:42:09 -0700827 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700828 framework_target_files_dir=framework_target_files_temp_dir,
829 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700830 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700831 framework_partition_set=framework_partition_set,
832 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700833 file_name='apkcerts.txt')
834
835 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700836 framework_target_files_dir=framework_target_files_temp_dir,
837 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700838 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700839 framework_partition_set=framework_partition_set,
840 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700841 file_name='apexkeys.txt')
842
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800843
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900844def create_merged_package(temp_dir, framework_target_files, framework_item_list,
845 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700846 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700847 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800848
849 Args:
850 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700851 input target files packages, and also a scratch directory that we use for
852 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700853 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700854 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700855 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700856 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700857 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700858 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700859 vendor_target_files: The name of the zip archive containing the vendor
860 partial target files package.
861 vendor_item_list: The list of items to extract from the partial vendor
862 target files package as is, meaning these items will land in the output
863 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700864 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -0700865 framework_misc_info_keys: A list of keys to obtain from the framework
866 instance of META/misc_info.txt. The remaining keys should come from the
867 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700868 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700869 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800870
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900871 Returns:
872 Path to merged package under temp directory.
873 """
Daniel Normandbbf5a32020-10-22 16:03:32 -0700874 # Extract "as is" items from the input framework and vendor partial target
875 # files packages directly into the output temporary directory, since these items
876 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800877
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800878 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -0800879 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700880 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800881 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700882 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -0800883 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700884 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800885 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700886 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800887
Daniel Normandbbf5a32020-10-22 16:03:32 -0700888 # Perform special case processing on META/* items.
889 # After this function completes successfully, all the files we need to create
890 # the output target files package are in place.
891 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
892 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700893 extract_items(
894 target_files=framework_target_files,
895 target_files_temp_dir=framework_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700896 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800897 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700898 target_files=vendor_target_files,
899 target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700900 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800901 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700902 framework_target_files_temp_dir=framework_target_files_temp_dir,
903 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800904 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700905 framework_misc_info_keys=framework_misc_info_keys,
906 framework_partition_set=item_list_to_partition_set(framework_item_list),
907 vendor_partition_set=item_list_to_partition_set(vendor_item_list))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800908
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900909 return output_target_files_temp_dir
910
911
912def generate_images(target_files_dir, rebuild_recovery):
913 """Generate images from target files.
914
915 This function takes merged output temporary directory and create images
916 from it.
917
918 Args:
919 target_files_dir: Path to merged temp directory.
920 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
921 devices and write it to the system image.
922 """
923
924 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800925
Daniel Normandbbf5a32020-10-22 16:03:32 -0700926 add_img_args = [
927 '--verbose',
928 '--add_missing',
929 ]
Bill Peckhame868aec2019-09-17 17:06:47 -0700930 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700931 if rebuild_recovery:
932 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900933 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800934
935 add_img_to_target_files.main(add_img_args)
936
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900937
938def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700939 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900940
941 Args:
942 target_dir: Path to the target file package which contains misc_info.txt for
943 detailed information for super image.
944 output_super_empty: If provided, copies a super_empty.img file from the
945 target files package to this path.
946 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700947 # Create super_empty.img using the merged misc_info.txt.
948
Daniel Norman4cc9df62019-07-18 10:11:07 -0700949 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700950
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900951 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
952 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700953
954 if use_dynamic_partitions != 'true' and output_super_empty:
955 raise ValueError(
956 'Building super_empty.img requires use_dynamic_partitions=true.')
957 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700958 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700959 build_super_image_args = [
960 misc_info_txt,
961 super_empty_img,
962 ]
963 build_super_image.main(build_super_image_args)
964
965 # Copy super_empty.img to the user-provided output_super_empty location.
966 if output_super_empty:
967 shutil.copyfile(super_empty_img, output_super_empty)
968
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700969
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900970def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700971 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900972
973 Args:
974 output_file: The name of the zip archive target files package.
975 source_dir: The target directory contains package to be archived.
976 temp_dir: Path to temporary directory for any intermediate files.
977 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800978 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900979 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700980 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800981
Daniel Normandbbf5a32020-10-22 16:03:32 -0700982 def files_from_path(target_path, extra_args=None):
983 """Gets files under the given path and return a sorted list."""
984 find_command = ['find', target_path] + (extra_args or [])
985 find_process = common.Run(
986 find_command, stdout=subprocess.PIPE, verbose=False)
987 return common.RunAndCheckOutput(['sort'],
988 stdin=find_process.stdout,
989 verbose=False)
990
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900991 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700992 other_content = files_from_path(
993 source_dir,
994 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800995
Tao Bao2ad4b822019-06-27 16:52:12 -0700996 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800997 f.write(meta_content)
998 f.write(other_content)
999
1000 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001001 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001002 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001003 '-o',
1004 output_zip,
1005 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001006 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001007 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001008 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001009 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001010
1011 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001012 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001013 logger.info('finished creating %s', output_file)
1014
1015 return output_zip
1016
1017
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001018def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1019 framework_misc_info_keys, vendor_target_files,
1020 vendor_item_list, output_target_files, output_dir,
1021 output_item_list, output_ota, output_img,
1022 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -07001023 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001024
1025 This function takes framework and vendor target files packages as input,
1026 performs various file extractions, special case processing, and finally
1027 creates a merged zip archive as output.
1028
1029 Args:
1030 temp_dir: The name of a directory we use when we extract items from the
1031 input target files packages, and also a scratch directory that we use for
1032 temporary files.
1033 framework_target_files: The name of the zip archive containing the framework
1034 partial target files package.
1035 framework_item_list: The list of items to extract from the partial framework
1036 target files package as is, meaning these items will land in the output
1037 target files package exactly as they appear in the input partial framework
1038 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001039 framework_misc_info_keys: A list of keys to obtain from the framework
1040 instance of META/misc_info.txt. The remaining keys should come from the
1041 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001042 vendor_target_files: The name of the zip archive containing the vendor
1043 partial target files package.
1044 vendor_item_list: The list of items to extract from the partial vendor
1045 target files package as is, meaning these items will land in the output
1046 target files package exactly as they appear in the input partial vendor
1047 target files package.
1048 output_target_files: The name of the output zip archive target files package
1049 created by merging framework and vendor.
1050 output_dir: The destination directory for saving merged files.
1051 output_item_list: The list of items to copy into the output_dir.
1052 output_ota: The name of the output zip archive ota package.
1053 output_img: The name of the output zip archive img package.
1054 output_super_empty: If provided, creates a super_empty.img file from the
1055 merged target files package and saves it at this path.
1056 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1057 devices and write it to the system image.
1058 """
1059
1060 logger.info('starting: merge framework %s and vendor %s into output %s',
1061 framework_target_files, vendor_target_files, output_target_files)
1062
1063 output_target_files_temp_dir = create_merged_package(
1064 temp_dir, framework_target_files, framework_item_list,
1065 vendor_target_files, vendor_item_list, framework_misc_info_keys,
1066 rebuild_recovery)
1067
Yifan Hongade0d3f2019-08-21 16:37:11 -07001068 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001069 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001070
Daniel Norman21c34f72020-11-11 17:25:50 -08001071 partition_map = common.PartitionMapFromTargetFiles(
1072 output_target_files_temp_dir)
1073
Daniel Normand3351562020-10-29 12:33:11 -07001074 # Generate and check for cross-partition violations of sharedUserId
1075 # values in APKs. This requires the input target-files packages to contain
1076 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001077 shareduid_violation_modules = os.path.join(
1078 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1079 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001080 violation = find_shareduid_violation.FindShareduidViolation(
1081 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001082
1083 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001084 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001085
1086 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001087 framework_partitions = item_list_to_partition_set(framework_item_list)
1088 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001089 shareduid_errors = common.SharedUidPartitionViolations(
1090 json.loads(violation), [framework_partitions, vendor_partitions])
1091 if shareduid_errors:
1092 for error in shareduid_errors:
1093 logger.error(error)
1094 raise ValueError('sharedUserId APK error. See %s' %
1095 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001096
Daniel Norman48603ff2021-02-22 15:15:24 -08001097 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001098 filtered_partitions = {
1099 partition: path
1100 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001101 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1102 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001103
1104 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001105 common.RunHostInitVerifier(
1106 product_out=output_target_files_temp_dir,
1107 partition_map=filtered_partitions)
1108
Daniel Norman48603ff2021-02-22 15:15:24 -08001109 # Check that the split sepolicy from the multiple builds can compile.
1110 split_sepolicy_cmd = compile_split_sepolicy(
1111 product_out=output_target_files_temp_dir,
1112 partition_map=filtered_partitions,
1113 output_policy=os.path.join(output_target_files_temp_dir,
1114 'META/combined.policy'))
1115 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1116 common.RunAndCheckOutput(split_sepolicy_cmd)
1117 # TODO(b/178864050): Run tests on the combined.policy file.
1118
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001119 generate_images(output_target_files_temp_dir, rebuild_recovery)
1120
1121 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1122
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001123 # Finally, create the output target files zip archive and/or copy the
1124 # output items to the output target files directory.
1125
1126 if output_dir:
1127 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1128
1129 if not output_target_files:
1130 return
1131
Daniel Normandb8cacc2021-04-09 15:34:43 -07001132 # Create the merged META/care_map.bp
1133 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
1134
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001135 output_zip = create_target_files_archive(output_target_files,
1136 output_target_files_temp_dir,
1137 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001138
Daniel Norman74eb74b2019-09-18 14:01:48 -07001139 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001140 if output_img:
1141 img_from_target_files.main([output_zip, output_img])
1142
Daniel Norman3b64ce12019-04-16 16:11:35 -07001143 # Create the OTA package from the merged target files package.
1144
1145 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001146 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001147
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001148
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001149def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001150 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001151
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001152 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001153 directory. It also cleans up the temporary directory.
1154
1155 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001156 func: The function to call. Should accept one parameter, the path to the
1157 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001158 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001159 """
1160
1161 # Create a temporary directory. This will serve as the parent of directories
1162 # we use when we extract items from the input target files packages, and also
1163 # a scratch directory that we use for temporary files.
1164
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001165 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1166
1167 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001168 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001169 finally:
1170 if keep_tmp:
1171 logger.info('keeping %s', temp_dir)
1172 else:
1173 common.Cleanup()
1174
1175
1176def main():
1177 """The main function.
1178
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001179 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001180 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001181 """
1182
1183 common.InitLogging()
1184
Bill Peckhamf753e152019-02-19 18:02:46 -08001185 def option_handler(o, a):
1186 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001187 logger.warning(
1188 '--system-target-files has been renamed to --framework-target-files')
1189 OPTIONS.framework_target_files = a
1190 elif o == '--framework-target-files':
1191 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001192 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001193 logger.warning(
1194 '--system-item-list has been renamed to --framework-item-list')
1195 OPTIONS.framework_item_list = a
1196 elif o == '--framework-item-list':
1197 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001198 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001199 logger.warning('--system-misc-info-keys has been renamed to '
1200 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001201 OPTIONS.framework_misc_info_keys = a
1202 elif o == '--framework-misc-info-keys':
1203 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001204 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001205 logger.warning(
1206 '--other-target-files has been renamed to --vendor-target-files')
1207 OPTIONS.vendor_target_files = a
1208 elif o == '--vendor-target-files':
1209 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001210 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001211 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001212 OPTIONS.vendor_item_list = a
1213 elif o == '--vendor-item-list':
1214 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001215 elif o == '--output-target-files':
1216 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001217 elif o == '--output-dir':
1218 OPTIONS.output_dir = a
1219 elif o == '--output-item-list':
1220 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001221 elif o == '--output-ota':
1222 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001223 elif o == '--output-img':
1224 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001225 elif o == '--output-super-empty':
1226 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001227 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001228 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001229 elif o == '--allow-duplicate-apkapex-keys':
1230 OPTIONS.allow_duplicate_apkapex_keys = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001231 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001232 OPTIONS.keep_tmp = True
1233 else:
1234 return False
1235 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001236
Bill Peckhamf753e152019-02-19 18:02:46 -08001237 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001238 sys.argv[1:],
1239 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001240 extra_long_opts=[
1241 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001242 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001243 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001244 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001245 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001246 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001247 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001248 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001249 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001250 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001251 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001252 'output-dir=',
1253 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001254 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001255 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001256 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001257 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001258 'allow-duplicate-apkapex-keys',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001259 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001260 ],
1261 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001262
Tao Bao2ad4b822019-06-27 16:52:12 -07001263 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001264 if (args or OPTIONS.framework_target_files is None or
1265 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001266 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001267 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001268 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001269 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001270
Daniel Normand5d70ea2019-06-05 15:13:43 -07001271 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001272 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001273 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001274 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001275
Daniel Normand5d70ea2019-06-05 15:13:43 -07001276 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001277 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001278 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001279 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001280 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001281
Daniel Normand5d70ea2019-06-05 15:13:43 -07001282 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001283 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001284 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001285 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001286
Daniel Normanfdb38812019-04-15 09:47:24 -07001287 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001288 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001289 else:
1290 output_item_list = None
1291
Daniel Normane5964522019-03-19 10:32:03 -07001292 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001293 framework_item_list=framework_item_list,
1294 framework_misc_info_keys=framework_misc_info_keys,
1295 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001296 sys.exit(1)
1297
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001298 call_func_with_temp_dir(
1299 lambda temp_dir: merge_target_files(
1300 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001301 framework_target_files=OPTIONS.framework_target_files,
1302 framework_item_list=framework_item_list,
1303 framework_misc_info_keys=framework_misc_info_keys,
1304 vendor_target_files=OPTIONS.vendor_target_files,
1305 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001306 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001307 output_dir=OPTIONS.output_dir,
1308 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001309 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001310 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001311 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001312 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001313
1314
1315if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001316 main()