blob: c1fa9e7d32c756871e6e4fbcdb977acae1a4dfd3 [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
Daniel Norman571e1822021-06-25 17:18:25 -070081 --rebuild-sepolicy
82 If provided, rebuilds odm.img or vendor.img to include merged sepolicy
83 files. If odm is present then odm is preferred.
84
85 --vendor-otatools otatools.zip
86 If provided, use this otatools.zip when recompiling the odm or vendor
87 image to include sepolicy.
88
Bill Peckham364c1cc2019-03-29 18:27:23 -070089 --keep-tmp
90 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080091"""
92
93from __future__ import print_function
94
Bill Peckhame9eb5f92019-02-01 15:52:10 -080095import fnmatch
Daniel Normand3351562020-10-29 12:33:11 -070096import json
Bill Peckhame9eb5f92019-02-01 15:52:10 -080097import logging
98import os
Bill Peckham19c3feb2020-03-20 18:31:43 -070099import re
Daniel Normanfdb38812019-04-15 09:47:24 -0700100import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -0700101import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800102import sys
103import zipfile
Daniel Norman48603ff2021-02-22 15:15:24 -0800104from xml.etree import ElementTree
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800105
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800106import add_img_to_target_files
Daniel Normane9af70a2021-04-15 16:39:22 -0700107import apex_utils
Daniel Normandb8cacc2021-04-09 15:34:43 -0700108import build_image
Daniel Normanf0318252019-04-15 11:34:56 -0700109import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -0700110import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -0700111import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700112import img_from_target_files
Daniel Normanb8d52a22020-10-26 17:55:00 -0700113import find_shareduid_violation
Daniel Norman3b64ce12019-04-16 16:11:35 -0700114import ota_from_target_files
Daniel Normandb8cacc2021-04-09 15:34:43 -0700115import sparse_img
116import verity_utils
117
118from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800119
120logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -0700121
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800122OPTIONS = common.OPTIONS
Bill Peckhamcb848172020-04-03 12:50:47 -0700123# Always turn on verbose logging.
124OPTIONS.verbose = True
Daniel Normand5d70ea2019-06-05 15:13:43 -0700125OPTIONS.framework_target_files = None
126OPTIONS.framework_item_list = None
127OPTIONS.framework_misc_info_keys = None
128OPTIONS.vendor_target_files = None
129OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800130OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700131OPTIONS.output_dir = None
132OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700133OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700134OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700135OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700136# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700137OPTIONS.rebuild_recovery = False
Daniel Normanb0c75912020-09-24 14:30:21 -0700138# TODO(b/150582573): Remove this option.
139OPTIONS.allow_duplicate_apkapex_keys = False
Daniel Norman571e1822021-06-25 17:18:25 -0700140OPTIONS.vendor_otatools = None
141OPTIONS.rebuild_sepolicy = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800142OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800143
Bill Peckham19c3feb2020-03-20 18:31:43 -0700144# In an item list (framework or vendor), we may see entries that select whole
145# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the
146# system partition). The following regex matches this and extracts the
147# partition name.
148
149PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$')
150
Bill Peckham5c7b0342020-04-03 15:36:23 -0700151# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
152# the file. We use these partition tags to filter the entries in those files
153# from the two different target files packages to produce a merged apexkeys.txt
154# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
155# like this: 'partition="product"'. We use the group syntax grab the value of
156# the tag. We use non-greedy matching in case there are other fields on the
157# same line.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700158
Bill Peckham5c7b0342020-04-03 15:36:23 -0700159PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700160
161# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
162# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
163
164MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
165
Daniel Normand5d70ea2019-06-05 15:13:43 -0700166# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
167# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800168# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700169# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800170
Daniel Normand5d70ea2019-06-05 15:13:43 -0700171DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800172 'META/apkcerts.txt',
173 'META/filesystem_config.txt',
174 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800175 'META/update_engine_config.txt',
176 'PRODUCT/*',
177 'ROOT/*',
178 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700179)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800180
Daniel Normand5d70ea2019-06-05 15:13:43 -0700181# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700182# framework instance of META/misc_info.txt. The remaining keys should come
183# from the vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800184
Daniel Normand5d70ea2019-06-05 15:13:43 -0700185DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800186 'avb_system_hashtree_enable',
187 'avb_system_add_hashtree_footer_args',
188 'avb_system_key_path',
189 'avb_system_algorithm',
190 'avb_system_rollback_index_location',
191 'avb_product_hashtree_enable',
192 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900193 'avb_system_ext_hashtree_enable',
194 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800195 'system_root_image',
196 'root_dir',
197 'ab_update',
198 'default_system_dev_certificate',
199 'system_size',
Chris Gross203191b2020-05-30 02:39:12 +0000200 'building_system_image',
201 'building_system_ext_image',
202 'building_product_image',
Daniel Normanedf12472019-05-22 10:47:08 -0700203)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800204
Daniel Normand5d70ea2019-06-05 15:13:43 -0700205# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
206# vendor target files package as is, meaning these items will land in the output
207# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800208# files package.
209
Daniel Normand5d70ea2019-06-05 15:13:43 -0700210DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800211 'META/boot_filesystem_config.txt',
212 'META/otakeys.txt',
213 'META/releasetools.py',
214 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800215 'BOOT/*',
216 'DATA/*',
217 'ODM/*',
218 'OTA/android-info.txt',
219 'PREBUILT_IMAGES/*',
220 'RADIO/*',
221 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700222)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800223
Daniel Normanedf12472019-05-22 10:47:08 -0700224# The merge config lists should not attempt to extract items from both
225# builds for any of the following partitions. The partitions in
226# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700227# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700228
229SINGLE_BUILD_PARTITIONS = (
230 'BOOT/',
231 'DATA/',
232 'ODM/',
233 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900234 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700235 'RADIO/',
236 'RECOVERY/',
237 'ROOT/',
238 'SYSTEM/',
239 'SYSTEM_OTHER/',
240 'VENDOR/',
Yifan Hongcfb917a2020-05-07 14:58:20 -0700241 'VENDOR_DLKM/',
Yifan Hongf496f1b2020-07-15 16:52:59 -0700242 'ODM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700243)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800244
245
Chris Grossfabf50a2019-05-02 12:42:09 -0700246def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700247 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700248
Tao Bao2ad4b822019-06-27 16:52:12 -0700249 This function sorts the contents of the list or dict and then writes the
250 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700251
252 Args:
253 data: The list or dict to sort and write.
254 path: Path to the file to write the sorted values to. The file at path will
255 be overridden if it exists.
256 """
257 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700258 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700259 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
260 data, dict) else '{}\n'.format(entry)
261 output.write(out_str)
262
263
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800264def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700265 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800266
267 This function extracts from the specified target files zip archive into the
268 specified temporary directory, the items specified in the extract item list.
269
270 Args:
271 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800272 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700273 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800274 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800275 """
276
277 logger.info('extracting from %s', target_files)
278
279 # Filter the extract_item_list to remove any items that do not exist in the
280 # zip file. Otherwise, the extraction step will fail.
281
Daniel Norman4cc9df62019-07-18 10:11:07 -0700282 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800283 target_files_namelist = target_files_zipfile.namelist()
284
285 filtered_extract_item_list = []
286 for pattern in extract_item_list:
287 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
288 if not matching_namelist:
289 logger.warning('no match for %s', pattern)
290 else:
291 filtered_extract_item_list.append(pattern)
292
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800293 # Extract from target_files into target_files_temp_dir the
294 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800295
Daniel Normane5b134a2019-04-17 14:54:06 -0700296 common.UnzipToDir(target_files, target_files_temp_dir,
297 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800298
299
Daniel Normanfdb38812019-04-15 09:47:24 -0700300def copy_items(from_dir, to_dir, patterns):
301 """Similar to extract_items() except uses an input dir instead of zip."""
302 file_paths = []
303 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700304 file_paths.extend(
305 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
306 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700307
308 filtered_file_paths = set()
309 for pattern in patterns:
310 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
311
312 for file_path in filtered_file_paths:
313 original_file_path = os.path.join(from_dir, file_path)
314 copied_file_path = os.path.join(to_dir, file_path)
315 copied_file_dir = os.path.dirname(copied_file_path)
316 if not os.path.exists(copied_file_dir):
317 os.makedirs(copied_file_dir)
318 if os.path.islink(original_file_path):
319 os.symlink(os.readlink(original_file_path), copied_file_path)
320 else:
321 shutil.copyfile(original_file_path, copied_file_path)
322
323
Daniel Normand5d70ea2019-06-05 15:13:43 -0700324def validate_config_lists(framework_item_list, framework_misc_info_keys,
325 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700326 """Performs validations on the merge config lists.
327
328 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700329 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700330 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700331 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700332 instance of META/misc_info.txt. The remaining keys should come from the
333 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700334 vendor_item_list: The list of items to extract from the partial vendor
335 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700336
337 Returns:
338 False if a validation fails, otherwise true.
339 """
Daniel Normanedf12472019-05-22 10:47:08 -0700340 has_error = False
341
Daniel Normand5d70ea2019-06-05 15:13:43 -0700342 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
343 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700344
Daniel Normand5d70ea2019-06-05 15:13:43 -0700345 combined_item_set = set(framework_item_list)
346 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700347
348 # Check that the merge config lists are not missing any item specified
349 # by the default config lists.
350 difference = default_combined_item_set.difference(combined_item_set)
351 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700352 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700353 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700354 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700355 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700356 has_error = True
357
Daniel Normandbbf5a32020-10-22 16:03:32 -0700358 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700359 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700360 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
361 in_framework = (
362 any(item.startswith(partition) for item in framework_item_list) or
363 image_path in framework_item_list)
364 in_vendor = (
365 any(item.startswith(partition) for item in vendor_item_list) or
366 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700367 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700368 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700369 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900370 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700371 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700372 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700373
Daniel Normandb8cacc2021-04-09 15:34:43 -0700374 if ('dynamic_partition_list'
375 in framework_misc_info_keys) or ('super_partition_groups'
376 in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700377 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700378 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700379 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700380
Daniel Normanedf12472019-05-22 10:47:08 -0700381 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700382
383
Daniel Normand5d70ea2019-06-05 15:13:43 -0700384def process_ab_partitions_txt(framework_target_files_temp_dir,
385 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700386 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700387 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800388
Tao Bao2ad4b822019-06-27 16:52:12 -0700389 This function merges the contents of the META/ab_partitions.txt files from the
390 framework directory and the vendor directory, placing the merged result in the
391 output directory. The precondition in that the files are already extracted.
392 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700393 merged content. The format for each ab_partitions.txt is one partition name
394 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800395
396 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700397 framework_target_files_temp_dir: The name of a directory containing the
398 special items extracted from the framework target files package.
399 vendor_target_files_temp_dir: The name of a directory containing the special
400 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700401 output_target_files_temp_dir: The name of a directory that will be used to
402 create the output target files package after all the special cases are
403 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800404 """
405
Daniel Normand5d70ea2019-06-05 15:13:43 -0700406 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
407 'META', 'ab_partitions.txt')
408
409 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700410 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800411
Daniel Normand5d70ea2019-06-05 15:13:43 -0700412 with open(framework_ab_partitions_txt) as f:
413 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800414
Daniel Normand5d70ea2019-06-05 15:13:43 -0700415 with open(vendor_ab_partitions_txt) as f:
416 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800417
Daniel Normand5d70ea2019-06-05 15:13:43 -0700418 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800419
Daniel Normane5b134a2019-04-17 14:54:06 -0700420 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
421 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800422
Chris Grossfabf50a2019-05-02 12:42:09 -0700423 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800424
425
Daniel Normand5d70ea2019-06-05 15:13:43 -0700426def process_misc_info_txt(framework_target_files_temp_dir,
427 vendor_target_files_temp_dir,
428 output_target_files_temp_dir,
429 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700430 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800431
432 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700433 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800434 output directory. The precondition in that the files are already extracted.
435 The post condition is that the output META/misc_info.txt contains the merged
436 content.
437
438 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700439 framework_target_files_temp_dir: The name of a directory containing the
440 special items extracted from the framework target files package.
441 vendor_target_files_temp_dir: The name of a directory containing the special
442 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700443 output_target_files_temp_dir: The name of a directory that will be used to
444 create the output target files package after all the special cases are
445 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700446 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700447 instance of META/misc_info.txt. The remaining keys should come from the
448 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800449 """
450
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900451 misc_info_path = ['META', 'misc_info.txt']
452 framework_dict = common.LoadDictionaryFromFile(
453 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800454
Daniel Normand5d70ea2019-06-05 15:13:43 -0700455 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800456
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900457 merged_dict = common.LoadDictionaryFromFile(
458 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800459
Daniel Normand5d70ea2019-06-05 15:13:43 -0700460 # Replace certain values in merged_dict with values from
461 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800462
Daniel Normand5d70ea2019-06-05 15:13:43 -0700463 for key in framework_misc_info_keys:
464 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800465
Daniel Norman19b9fe92019-03-19 14:48:02 -0700466 # Merge misc info keys used for Dynamic Partitions.
Daniel Normandb8cacc2021-04-09 15:34:43 -0700467 if (merged_dict.get('use_dynamic_partitions')
468 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700469 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800470 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700471 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700472 # Ensure that add_img_to_target_files rebuilds super split images for
473 # devices that retrofit dynamic partitions. This flag may have been set to
474 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700475 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700476
Daniel Norman38888d32020-11-19 14:51:15 -0800477 # If AVB is enabled then ensure that we build vbmeta.img.
478 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
479 # skip building an incomplete vbmeta.img.
480 if merged_dict.get('avb_enable') == 'true':
481 merged_dict['avb_building_vbmeta_image'] = 'true'
482
Daniel Normand5d70ea2019-06-05 15:13:43 -0700483 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700484 # depending on which dictionary the key came from.
485 # Only the file basename is required because all selinux_fc properties are
486 # replaced with the full path to the file under META/ when misc_info.txt is
487 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700488 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700489 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700490 merged_dict[key] = 'vendor_file_contexts.bin'
491 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700492 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700493 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700494
Daniel Normane5b134a2019-04-17 14:54:06 -0700495 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
496 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700497 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800498
499
Daniel Normand5d70ea2019-06-05 15:13:43 -0700500def process_dynamic_partitions_info_txt(framework_target_files_dir,
501 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700502 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700503 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700504
505 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700506 files from the framework directory and the vendor directory, placing the
507 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700508
Daniel Normand5d70ea2019-06-05 15:13:43 -0700509 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700510 directory does not exist.
511
512 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700513 framework_target_files_dir: The name of a directory containing the special
514 items extracted from the framework target files package.
515 vendor_target_files_dir: The name of a directory containing the special
516 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700517 output_target_files_dir: The name of a directory that will be used to create
518 the output target files package after all the special cases are processed.
519 """
520
521 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700522 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700523 'dynamic_partitions_info.txt')):
524 return
525
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900526 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700527
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900528 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
529 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
530 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
531 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700532
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700533 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700534 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800535 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700536
537 output_dynamic_partitions_info_txt = os.path.join(
538 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700539 write_sorted_data(
540 data=merged_dynamic_partitions_dict,
541 path=output_dynamic_partitions_info_txt)
542
543
Bill Peckham19c3feb2020-03-20 18:31:43 -0700544def item_list_to_partition_set(item_list):
545 """Converts a target files item list to a partition set.
546
547 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
548 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
549 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
550 contents of a partition of the same name. Other items in the list, such as the
551 'OTA' example contain metadata. This function iterates such a list, returning
552 a set that contains the partition entries.
553
554 Args:
555 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700556
Bill Peckham19c3feb2020-03-20 18:31:43 -0700557 Returns:
558 A set of partitions extracted from the list of items.
559 """
560
561 partition_set = set()
562
563 for item in item_list:
564 match = PARTITION_ITEM_PATTERN.search(item.strip())
565 partition_tag = match.group(1).lower() if match else None
566
567 if partition_tag:
568 partition_set.add(partition_tag)
569
570 return partition_set
571
572
Daniel Normand5d70ea2019-06-05 15:13:43 -0700573def process_apex_keys_apk_certs_common(framework_target_files_dir,
574 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700575 output_target_files_dir,
576 framework_partition_set,
577 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700578 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700579
580 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700581 META/apkcerts.txt files from the framework directory and the vendor directory,
582 placing the merged result in the output directory. The precondition in that
583 the files are already extracted. The post condition is that the output
584 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700585
586 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700587 framework_target_files_dir: The name of a directory containing the special
588 items extracted from the framework target files package.
589 vendor_target_files_dir: The name of a directory containing the special
590 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700591 output_target_files_dir: The name of a directory that will be used to create
592 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700593 framework_partition_set: Partitions that are considered framework
594 partitions. Used to filter apexkeys.txt and apkcerts.txt.
595 vendor_partition_set: Partitions that are considered vendor partitions. Used
596 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700597 file_name: The name of the file to merge. One of apkcerts.txt or
598 apexkeys.txt.
599 """
600
601 def read_helper(d):
602 temp = {}
603 file_path = os.path.join(d, 'META', file_name)
604 with open(file_path) as f:
605 for line in f:
606 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700607 name = line.split()[0]
608 match = MODULE_KEY_PATTERN.search(name)
609 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700610 return temp
611
Daniel Normand5d70ea2019-06-05 15:13:43 -0700612 framework_dict = read_helper(framework_target_files_dir)
613 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700614 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700615
Bill Peckham19c3feb2020-03-20 18:31:43 -0700616 def filter_into_merged_dict(item_dict, partition_set):
617 for key, value in item_dict.items():
618 match = PARTITION_TAG_PATTERN.search(value)
619
620 if match is None:
621 raise ValueError('Entry missing partition tag: %s' % value)
622
623 partition_tag = match.group(1)
624
625 if partition_tag in partition_set:
626 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700627 if OPTIONS.allow_duplicate_apkapex_keys:
628 # TODO(b/150582573) Always raise on duplicates.
629 logger.warning('Duplicate key %s' % key)
630 continue
631 else:
632 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700633
634 merged_dict[key] = value
635
636 filter_into_merged_dict(framework_dict, framework_partition_set)
637 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700638
639 output_file = os.path.join(output_target_files_dir, 'META', file_name)
640
Bill Peckham19c3feb2020-03-20 18:31:43 -0700641 # The following code is similar to write_sorted_data, but different enough
642 # that we couldn't use that function. We need the output to be sorted by the
643 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
644 # allows the sort to be consistent with the framework/vendor input data and
645 # eases comparison of input data with merged data.
646 with open(output_file, 'w') as output:
647 for key in sorted(merged_dict.keys()):
648 out_str = merged_dict[key] + '\n'
649 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700650
651
Daniel Normand5d70ea2019-06-05 15:13:43 -0700652def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700653 output_target_files_dir):
654 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700655 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
656 'framework_file_contexts.bin')
657 if not os.path.exists(framework_fc_path):
658 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
659 'file_contexts.bin')
660 if not os.path.exists(framework_fc_path):
661 raise ValueError('Missing framework file_contexts.bin.')
662 shutil.copyfile(
663 framework_fc_path,
664 os.path.join(output_target_files_dir, 'META',
665 'framework_file_contexts.bin'))
666
667 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
668 'vendor_file_contexts.bin')
669 if not os.path.exists(vendor_fc_path):
670 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700671 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700672 if not os.path.exists(vendor_fc_path):
673 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700674 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700675 vendor_fc_path,
676 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700677
678
Daniel Norman571e1822021-06-25 17:18:25 -0700679def compile_split_sepolicy(product_out, partition_map):
Daniel Norman48603ff2021-02-22 15:15:24 -0800680 """Uses secilc to compile a split sepolicy file.
681
682 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
683
684 Args:
685 product_out: PRODUCT_OUT directory, containing partition directories.
686 partition_map: A map of partition name -> relative path within product_out.
Daniel Norman48603ff2021-02-22 15:15:24 -0800687
688 Returns:
689 A command list that can be executed to create the compiled sepolicy.
690 """
691
692 def get_file(partition, path):
693 if partition not in partition_map:
694 logger.warning('Cannot load SEPolicy files for missing partition %s',
695 partition)
696 return None
697 return os.path.join(product_out, partition_map[partition], path)
698
699 # Load the kernel sepolicy version from the FCM. This is normally provided
700 # directly to selinux.cpp as a build flag, but is also available in this file.
701 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
702 if not fcm_file or not os.path.exists(fcm_file):
703 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
704 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
705 'sepolicy/kernel-sepolicy-version').text
706
707 # Load the vendor's plat sepolicy version. This is the version used for
708 # locating sepolicy mapping files.
709 vendor_plat_version_file = get_file('vendor',
710 'etc/selinux/plat_sepolicy_vers.txt')
711 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000712 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800713 raise ExternalError('Missing required sepolicy file %s',
714 vendor_plat_version_file)
715 with open(vendor_plat_version_file) as f:
716 vendor_plat_version = f.read().strip()
717
718 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
719 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
720 cmd.extend(['-c', kernel_sepolicy_version])
Daniel Norman571e1822021-06-25 17:18:25 -0700721 cmd.extend(['-o', os.path.join(product_out, 'META/combined_sepolicy')])
Daniel Norman48603ff2021-02-22 15:15:24 -0800722 cmd.extend(['-f', '/dev/null'])
723
724 required_policy_files = (
725 ('system', 'etc/selinux/plat_sepolicy.cil'),
726 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
727 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
728 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
729 )
730 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
731 required_policy_files)):
732 if not policy or not os.path.exists(policy):
733 raise ExternalError('Missing required sepolicy file %s', policy)
734 cmd.append(policy)
735
736 optional_policy_files = (
737 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
738 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
739 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
740 ('product', 'etc/selinux/product_sepolicy.cil'),
741 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
742 ('odm', 'etc/selinux/odm_sepolicy.cil'),
743 )
744 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
745 optional_policy_files)):
746 if policy and os.path.exists(policy):
747 cmd.append(policy)
748
749 return cmd
750
751
Daniel Normane9af70a2021-04-15 16:39:22 -0700752def validate_merged_apex_info(output_target_files_dir, partitions):
753 """Validates the APEX files in the merged target files directory.
754
755 Checks the APEX files in all possible preinstalled APEX directories.
756 Depends on the <partition>/apex/* APEX files within partitions.
757
758 Args:
Daniel Norman571e1822021-06-25 17:18:25 -0700759 output_target_files_dir: Output directory containing merged partition
760 directories.
Daniel Normane9af70a2021-04-15 16:39:22 -0700761 partitions: A list of all the partitions in the output directory.
762
763 Raises:
764 RuntimeError: if apex_utils fails to parse any APEX file.
765 ExternalError: if the same APEX package is provided by multiple partitions.
766 """
767 apex_packages = set()
768
769 apex_partitions = ('system', 'system_ext', 'product', 'vendor')
770 for partition in filter(lambda p: p in apex_partitions, partitions):
771 apex_info = apex_utils.GetApexInfoFromTargetFiles(
772 output_target_files_dir, partition, compressed_only=False)
773 partition_apex_packages = set([info.package_name for info in apex_info])
774 duplicates = apex_packages.intersection(partition_apex_packages)
775 if duplicates:
776 raise ExternalError(
777 'Duplicate APEX packages found in multiple partitions: %s' %
778 ' '.join(duplicates))
779 apex_packages.update(partition_apex_packages)
780
781
Daniel Normandb8cacc2021-04-09 15:34:43 -0700782def generate_care_map(partitions, output_target_files_dir):
783 """Generates a merged META/care_map.pb file in the output target files dir.
784
785 Depends on the info dict from META/misc_info.txt, as well as built images
786 within IMAGES/.
787
788 Args:
789 partitions: A list of partitions to potentially include in the care map.
790 output_target_files_dir: The name of a directory that will be used to create
791 the output target files package after all the special cases are processed.
792 """
793 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir)
794 partition_image_map = {}
795 for partition in partitions:
796 image_path = os.path.join(output_target_files_dir, 'IMAGES',
797 '{}.img'.format(partition))
798 if os.path.exists(image_path):
799 partition_image_map[partition] = image_path
800 # Regenerated images should have their image_size property already set.
801 image_size_prop = '{}_image_size'.format(partition)
802 if image_size_prop not in OPTIONS.info_dict:
803 # Images copied directly from input target files packages will need
804 # their image sizes calculated.
805 partition_size = sparse_img.GetImagePartitionSize(image_path)
806 image_props = build_image.ImagePropFromGlobalDict(
807 OPTIONS.info_dict, partition)
808 verity_image_builder = verity_utils.CreateVerityImageBuilder(
809 image_props)
810 image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
811 OPTIONS.info_dict[image_size_prop] = image_size
812
813 AddCareMapForAbOta(
814 os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
815 PARTITIONS_WITH_CARE_MAP, partition_image_map)
816
817
Daniel Normand5d70ea2019-06-05 15:13:43 -0700818def process_special_cases(framework_target_files_temp_dir,
819 vendor_target_files_temp_dir,
820 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700821 framework_misc_info_keys, framework_partition_set,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700822 vendor_partition_set):
Tao Bao2ad4b822019-06-27 16:52:12 -0700823 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800824
825 Certain files in the output target files package require special-case
826 processing. This function performs all that special-case processing.
827
828 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700829 framework_target_files_temp_dir: The name of a directory containing the
830 special items extracted from the framework target files package.
831 vendor_target_files_temp_dir: The name of a directory containing the special
832 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700833 output_target_files_temp_dir: The name of a directory that will be used to
834 create the output target files package after all the special cases are
835 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700836 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700837 instance of META/misc_info.txt. The remaining keys should come from the
838 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700839 framework_partition_set: Partitions that are considered framework
840 partitions. Used to filter apexkeys.txt and apkcerts.txt.
841 vendor_partition_set: Partitions that are considered vendor partitions. Used
842 to filter apexkeys.txt and apkcerts.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800843 """
844
Daniel Normand5d70ea2019-06-05 15:13:43 -0700845 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700846 process_ab_partitions_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,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700849 output_target_files_temp_dir=output_target_files_temp_dir)
850
Daniel Norman72c626f2019-05-13 15:58:14 -0700851 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700852 framework_target_files_dir=framework_target_files_temp_dir,
853 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700854 output_target_files_dir=output_target_files_temp_dir)
855
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800856 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700857 framework_target_files_temp_dir=framework_target_files_temp_dir,
858 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800859 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700860 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800861
Daniel Normana61cde02019-05-03 14:19:13 -0700862 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700863 framework_target_files_dir=framework_target_files_temp_dir,
864 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700865 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700866
Chris Grossfabf50a2019-05-02 12:42:09 -0700867 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700868 framework_target_files_dir=framework_target_files_temp_dir,
869 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700870 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700871 framework_partition_set=framework_partition_set,
872 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700873 file_name='apkcerts.txt')
874
875 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700876 framework_target_files_dir=framework_target_files_temp_dir,
877 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700878 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700879 framework_partition_set=framework_partition_set,
880 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700881 file_name='apexkeys.txt')
882
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800883
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900884def create_merged_package(temp_dir, framework_target_files, framework_item_list,
885 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700886 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700887 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800888
889 Args:
890 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700891 input target files packages, and also a scratch directory that we use for
892 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700893 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700894 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700895 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700896 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700897 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700898 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700899 vendor_target_files: The name of the zip archive containing the vendor
900 partial target files package.
901 vendor_item_list: The list of items to extract from the partial vendor
902 target files package as is, meaning these items will land in the output
903 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700904 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -0700905 framework_misc_info_keys: A list of keys to obtain from the framework
906 instance of META/misc_info.txt. The remaining keys should come from the
907 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700908 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700909 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800910
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900911 Returns:
912 Path to merged package under temp directory.
913 """
Daniel Normandbbf5a32020-10-22 16:03:32 -0700914 # Extract "as is" items from the input framework and vendor partial target
915 # files packages directly into the output temporary directory, since these items
916 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800917
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800918 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -0800919 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700920 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800921 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700922 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -0800923 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700924 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800925 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700926 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800927
Daniel Normandbbf5a32020-10-22 16:03:32 -0700928 # Perform special case processing on META/* items.
929 # After this function completes successfully, all the files we need to create
930 # the output target files package are in place.
931 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
932 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700933 extract_items(
934 target_files=framework_target_files,
935 target_files_temp_dir=framework_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700936 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800937 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700938 target_files=vendor_target_files,
939 target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Normandbbf5a32020-10-22 16:03:32 -0700940 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -0800941 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700942 framework_target_files_temp_dir=framework_target_files_temp_dir,
943 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800944 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700945 framework_misc_info_keys=framework_misc_info_keys,
946 framework_partition_set=item_list_to_partition_set(framework_item_list),
947 vendor_partition_set=item_list_to_partition_set(vendor_item_list))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800948
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900949 return output_target_files_temp_dir
950
951
952def generate_images(target_files_dir, rebuild_recovery):
953 """Generate images from target files.
954
955 This function takes merged output temporary directory and create images
956 from it.
957
958 Args:
959 target_files_dir: Path to merged temp directory.
960 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
961 devices and write it to the system image.
962 """
963
964 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800965
Daniel Normandbbf5a32020-10-22 16:03:32 -0700966 add_img_args = [
967 '--verbose',
968 '--add_missing',
969 ]
Bill Peckhame868aec2019-09-17 17:06:47 -0700970 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700971 if rebuild_recovery:
972 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900973 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800974
975 add_img_to_target_files.main(add_img_args)
976
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900977
Daniel Norman571e1822021-06-25 17:18:25 -0700978def rebuild_image_with_sepolicy(target_files_dir,
979 vendor_otatools=None,
980 vendor_target_files=None):
981 """Rebuilds odm.img or vendor.img to include merged sepolicy files.
982
983 If odm is present then odm is preferred -- otherwise vendor is used.
984
985 Args:
986 target_files_dir: Path to the extracted merged target-files package.
987 vendor_otatools: If not None, path to an otatools.zip from the vendor build
988 that is used when recompiling the image.
989 vendor_target_files: Expected if vendor_otatools is not None. Path to the
990 vendor target-files zip.
991 """
992 partition = 'vendor'
993 if os.path.exists(os.path.join(target_files_dir, 'ODM')) or os.path.exists(
994 os.path.join(target_files_dir, 'IMAGES/odm.img')):
995 partition = 'odm'
996 partition_img = '{}.img'.format(partition)
997
998 logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
999
1000 # Copy the combined SEPolicy file and framework hashes to the image that is
1001 # being rebuilt.
1002 def copy_selinux_file(input_path, output_filename):
1003 shutil.copy(
1004 os.path.join(target_files_dir, input_path),
1005 os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
1006 output_filename))
1007
1008 copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy')
1009 copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256',
1010 'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256')
1011 copy_selinux_file(
1012 'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256',
1013 'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256')
1014 copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256',
1015 'precompiled_sepolicy.product_sepolicy_and_mapping.sha256')
1016
1017 if not vendor_otatools:
1018 # Remove the partition from the merged target-files archive. It will be
1019 # rebuilt later automatically by generate_images().
1020 os.remove(os.path.join(target_files_dir, 'IMAGES', partition_img))
1021 else:
1022 # TODO(b/192253131): Remove the need for vendor_otatools by fixing
1023 # backwards-compatibility issues when compiling images on R from S+.
1024 if not vendor_target_files:
1025 raise ValueError(
1026 'Expected vendor_target_files if vendor_otatools is not None.')
1027 logger.info(
1028 '%s recompilation will be performed using the vendor otatools.zip',
1029 partition_img)
1030
1031 # Unzip the vendor build's otatools.zip and target-files archive.
1032 vendor_otatools_dir = common.MakeTempDir(
1033 prefix='merge_target_files_vendor_otatools_')
1034 vendor_target_files_dir = common.MakeTempDir(
1035 prefix='merge_target_files_vendor_target_files_')
1036 common.UnzipToDir(vendor_otatools, vendor_otatools_dir)
1037 common.UnzipToDir(vendor_target_files, vendor_target_files_dir)
1038
1039 # Copy the partition contents from the merged target-files archive to the
1040 # vendor target-files archive.
1041 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
1042 shutil.copytree(
1043 os.path.join(target_files_dir, partition.upper()),
1044 os.path.join(vendor_target_files_dir, partition.upper()))
1045
1046 # Delete then rebuild the partition.
1047 os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
1048 rebuild_partition_command = [
1049 os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
1050 '--verbose',
1051 '--add_missing',
1052 vendor_target_files_dir,
1053 ]
1054 logger.info('Recompiling %s: %s', partition_img,
1055 ' '.join(rebuild_partition_command))
1056 common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
1057
1058 # Move the newly-created image to the merged target files dir.
1059 shutil.move(
1060 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
1061 os.path.join(target_files_dir, 'IMAGES', partition_img))
1062
1063
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001064def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -07001065 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001066
1067 Args:
1068 target_dir: Path to the target file package which contains misc_info.txt for
1069 detailed information for super image.
1070 output_super_empty: If provided, copies a super_empty.img file from the
1071 target files package to this path.
1072 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001073 # Create super_empty.img using the merged misc_info.txt.
1074
Daniel Norman4cc9df62019-07-18 10:11:07 -07001075 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001076
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +09001077 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
1078 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001079
1080 if use_dynamic_partitions != 'true' and output_super_empty:
1081 raise ValueError(
1082 'Building super_empty.img requires use_dynamic_partitions=true.')
1083 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001084 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001085 build_super_image_args = [
1086 misc_info_txt,
1087 super_empty_img,
1088 ]
1089 build_super_image.main(build_super_image_args)
1090
1091 # Copy super_empty.img to the user-provided output_super_empty location.
1092 if output_super_empty:
1093 shutil.copyfile(super_empty_img, output_super_empty)
1094
Daniel Normanb8a2f9d2019-04-24 12:55:51 -07001095
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001096def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -07001097 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001098
1099 Args:
1100 output_file: The name of the zip archive target files package.
1101 source_dir: The target directory contains package to be archived.
1102 temp_dir: Path to temporary directory for any intermediate files.
1103 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001104 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001105 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001106 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001107
Daniel Normandbbf5a32020-10-22 16:03:32 -07001108 def files_from_path(target_path, extra_args=None):
1109 """Gets files under the given path and return a sorted list."""
1110 find_command = ['find', target_path] + (extra_args or [])
1111 find_process = common.Run(
1112 find_command, stdout=subprocess.PIPE, verbose=False)
1113 return common.RunAndCheckOutput(['sort'],
1114 stdin=find_process.stdout,
1115 verbose=False)
1116
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001117 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001118 other_content = files_from_path(
1119 source_dir,
1120 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001121
Tao Bao2ad4b822019-06-27 16:52:12 -07001122 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001123 f.write(meta_content)
1124 f.write(other_content)
1125
1126 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001127 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001128 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001129 '-o',
1130 output_zip,
1131 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001132 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001133 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001134 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001135 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001136
1137 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001138 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001139 logger.info('finished creating %s', output_file)
1140
1141 return output_zip
1142
1143
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001144def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1145 framework_misc_info_keys, vendor_target_files,
1146 vendor_item_list, output_target_files, output_dir,
1147 output_item_list, output_ota, output_img,
Daniel Norman571e1822021-06-25 17:18:25 -07001148 output_super_empty, rebuild_recovery, vendor_otatools,
1149 rebuild_sepolicy):
Tao Bao2ad4b822019-06-27 16:52:12 -07001150 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001151
1152 This function takes framework and vendor target files packages as input,
1153 performs various file extractions, special case processing, and finally
1154 creates a merged zip archive as output.
1155
1156 Args:
1157 temp_dir: The name of a directory we use when we extract items from the
1158 input target files packages, and also a scratch directory that we use for
1159 temporary files.
1160 framework_target_files: The name of the zip archive containing the framework
1161 partial target files package.
1162 framework_item_list: The list of items to extract from the partial framework
1163 target files package as is, meaning these items will land in the output
1164 target files package exactly as they appear in the input partial framework
1165 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001166 framework_misc_info_keys: A list of keys to obtain from the framework
1167 instance of META/misc_info.txt. The remaining keys should come from the
1168 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001169 vendor_target_files: The name of the zip archive containing the vendor
1170 partial target files package.
1171 vendor_item_list: The list of items to extract from the partial vendor
1172 target files package as is, meaning these items will land in the output
1173 target files package exactly as they appear in the input partial vendor
1174 target files package.
1175 output_target_files: The name of the output zip archive target files package
1176 created by merging framework and vendor.
1177 output_dir: The destination directory for saving merged files.
1178 output_item_list: The list of items to copy into the output_dir.
1179 output_ota: The name of the output zip archive ota package.
1180 output_img: The name of the output zip archive img package.
1181 output_super_empty: If provided, creates a super_empty.img file from the
1182 merged target files package and saves it at this path.
1183 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1184 devices and write it to the system image.
Daniel Norman571e1822021-06-25 17:18:25 -07001185 vendor_otatools: Path to an otatools zip used for recompiling vendor images.
1186 rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
1187 vendor.img using a merged precompiled_sepolicy file.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001188 """
1189
1190 logger.info('starting: merge framework %s and vendor %s into output %s',
1191 framework_target_files, vendor_target_files, output_target_files)
1192
1193 output_target_files_temp_dir = create_merged_package(
1194 temp_dir, framework_target_files, framework_item_list,
1195 vendor_target_files, vendor_item_list, framework_misc_info_keys,
1196 rebuild_recovery)
1197
Yifan Hongade0d3f2019-08-21 16:37:11 -07001198 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001199 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001200
Daniel Norman21c34f72020-11-11 17:25:50 -08001201 partition_map = common.PartitionMapFromTargetFiles(
1202 output_target_files_temp_dir)
1203
Daniel Normand3351562020-10-29 12:33:11 -07001204 # Generate and check for cross-partition violations of sharedUserId
1205 # values in APKs. This requires the input target-files packages to contain
1206 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001207 shareduid_violation_modules = os.path.join(
1208 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1209 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001210 violation = find_shareduid_violation.FindShareduidViolation(
1211 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001212
1213 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001214 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001215
1216 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001217 framework_partitions = item_list_to_partition_set(framework_item_list)
1218 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001219 shareduid_errors = common.SharedUidPartitionViolations(
1220 json.loads(violation), [framework_partitions, vendor_partitions])
1221 if shareduid_errors:
1222 for error in shareduid_errors:
1223 logger.error(error)
1224 raise ValueError('sharedUserId APK error. See %s' %
1225 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001226
Daniel Norman48603ff2021-02-22 15:15:24 -08001227 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001228 filtered_partitions = {
1229 partition: path
1230 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001231 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1232 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001233
1234 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001235 common.RunHostInitVerifier(
1236 product_out=output_target_files_temp_dir,
1237 partition_map=filtered_partitions)
1238
Daniel Norman48603ff2021-02-22 15:15:24 -08001239 # Check that the split sepolicy from the multiple builds can compile.
Daniel Norman571e1822021-06-25 17:18:25 -07001240 split_sepolicy_cmd = compile_split_sepolicy(output_target_files_temp_dir,
1241 filtered_partitions)
Daniel Norman48603ff2021-02-22 15:15:24 -08001242 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1243 common.RunAndCheckOutput(split_sepolicy_cmd)
Daniel Norman571e1822021-06-25 17:18:25 -07001244 # Include the compiled policy in an image if requested.
1245 if rebuild_sepolicy:
1246 rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
1247 vendor_target_files)
Daniel Norman48603ff2021-02-22 15:15:24 -08001248
Daniel Normane9af70a2021-04-15 16:39:22 -07001249 # Run validation checks on the pre-installed APEX files.
1250 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
1251
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001252 generate_images(output_target_files_temp_dir, rebuild_recovery)
1253
1254 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1255
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001256 # Finally, create the output target files zip archive and/or copy the
1257 # output items to the output target files directory.
1258
1259 if output_dir:
1260 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1261
1262 if not output_target_files:
1263 return
1264
Daniel Normandb8cacc2021-04-09 15:34:43 -07001265 # Create the merged META/care_map.bp
1266 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
1267
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001268 output_zip = create_target_files_archive(output_target_files,
1269 output_target_files_temp_dir,
1270 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001271
Daniel Norman74eb74b2019-09-18 14:01:48 -07001272 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001273 if output_img:
1274 img_from_target_files.main([output_zip, output_img])
1275
Daniel Norman3b64ce12019-04-16 16:11:35 -07001276 # Create the OTA package from the merged target files package.
1277
1278 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001279 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001280
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001281
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001282def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001283 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001284
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001285 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001286 directory. It also cleans up the temporary directory.
1287
1288 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001289 func: The function to call. Should accept one parameter, the path to the
1290 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001291 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001292 """
1293
1294 # Create a temporary directory. This will serve as the parent of directories
1295 # we use when we extract items from the input target files packages, and also
1296 # a scratch directory that we use for temporary files.
1297
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001298 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1299
1300 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001301 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001302 finally:
1303 if keep_tmp:
1304 logger.info('keeping %s', temp_dir)
1305 else:
1306 common.Cleanup()
1307
1308
1309def main():
1310 """The main function.
1311
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001312 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001313 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001314 """
1315
1316 common.InitLogging()
1317
Bill Peckhamf753e152019-02-19 18:02:46 -08001318 def option_handler(o, a):
1319 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001320 logger.warning(
1321 '--system-target-files has been renamed to --framework-target-files')
1322 OPTIONS.framework_target_files = a
1323 elif o == '--framework-target-files':
1324 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001325 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001326 logger.warning(
1327 '--system-item-list has been renamed to --framework-item-list')
1328 OPTIONS.framework_item_list = a
1329 elif o == '--framework-item-list':
1330 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001331 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001332 logger.warning('--system-misc-info-keys has been renamed to '
1333 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001334 OPTIONS.framework_misc_info_keys = a
1335 elif o == '--framework-misc-info-keys':
1336 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001337 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001338 logger.warning(
1339 '--other-target-files has been renamed to --vendor-target-files')
1340 OPTIONS.vendor_target_files = a
1341 elif o == '--vendor-target-files':
1342 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001343 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001344 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001345 OPTIONS.vendor_item_list = a
1346 elif o == '--vendor-item-list':
1347 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001348 elif o == '--output-target-files':
1349 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001350 elif o == '--output-dir':
1351 OPTIONS.output_dir = a
1352 elif o == '--output-item-list':
1353 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001354 elif o == '--output-ota':
1355 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001356 elif o == '--output-img':
1357 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001358 elif o == '--output-super-empty':
1359 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001360 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001361 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001362 elif o == '--allow-duplicate-apkapex-keys':
1363 OPTIONS.allow_duplicate_apkapex_keys = True
Daniel Norman571e1822021-06-25 17:18:25 -07001364 elif o == '--vendor-otatools':
1365 OPTIONS.vendor_otatools = a
1366 elif o == '--rebuild-sepolicy':
1367 OPTIONS.rebuild_sepolicy = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001368 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001369 OPTIONS.keep_tmp = True
1370 else:
1371 return False
1372 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001373
Bill Peckhamf753e152019-02-19 18:02:46 -08001374 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001375 sys.argv[1:],
1376 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001377 extra_long_opts=[
1378 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001379 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001380 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001381 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001382 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001383 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001384 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001385 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001386 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001387 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001388 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001389 'output-dir=',
1390 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001391 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001392 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001393 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001394 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001395 'allow-duplicate-apkapex-keys',
Daniel Norman571e1822021-06-25 17:18:25 -07001396 'vendor-otatools=',
1397 'rebuild-sepolicy',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001398 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001399 ],
1400 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001401
Tao Bao2ad4b822019-06-27 16:52:12 -07001402 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001403 if (args or OPTIONS.framework_target_files is None or
1404 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001405 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001406 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001407 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001408 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001409
Daniel Normand5d70ea2019-06-05 15:13:43 -07001410 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001411 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001412 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001413 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001414
Daniel Normand5d70ea2019-06-05 15:13:43 -07001415 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001416 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001417 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001418 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001419 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001420
Daniel Normand5d70ea2019-06-05 15:13:43 -07001421 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001422 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001423 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001424 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001425
Daniel Normanfdb38812019-04-15 09:47:24 -07001426 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001427 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001428 else:
1429 output_item_list = None
1430
Daniel Normane5964522019-03-19 10:32:03 -07001431 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001432 framework_item_list=framework_item_list,
1433 framework_misc_info_keys=framework_misc_info_keys,
1434 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001435 sys.exit(1)
1436
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001437 call_func_with_temp_dir(
1438 lambda temp_dir: merge_target_files(
1439 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001440 framework_target_files=OPTIONS.framework_target_files,
1441 framework_item_list=framework_item_list,
1442 framework_misc_info_keys=framework_misc_info_keys,
1443 vendor_target_files=OPTIONS.vendor_target_files,
1444 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001445 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001446 output_dir=OPTIONS.output_dir,
1447 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001448 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001449 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001450 output_super_empty=OPTIONS.output_super_empty,
Daniel Norman571e1822021-06-25 17:18:25 -07001451 rebuild_recovery=OPTIONS.rebuild_recovery,
1452 vendor_otatools=OPTIONS.vendor_otatools,
1453 rebuild_sepolicy=OPTIONS.rebuild_sepolicy), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001454
1455
1456if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001457 main()