blob: 6b3b01fcc2a180bc5dd954c5c804347929d5e9ec [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.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -070091
92 The following only apply when using the VSDK to perform dexopt on vendor apps:
93
94 --framework-dexpreopt-config
95 If provided, the location of framwework's dexpreopt_config.zip.
96
97 --framework-dexpreopt-tools
98 if provided, the location of framework's dexpreopt_tools.zip.
99
100 --vendor-dexpreopt-config
101 If provided, the location of vendor's dexpreopt_config.zip.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800102"""
103
104from __future__ import print_function
105
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800106import fnmatch
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700107import glob
Daniel Normand3351562020-10-29 12:33:11 -0700108import json
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800109import logging
110import os
Bill Peckham19c3feb2020-03-20 18:31:43 -0700111import re
Daniel Normanfdb38812019-04-15 09:47:24 -0700112import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -0700113import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800114import sys
115import zipfile
Daniel Norman48603ff2021-02-22 15:15:24 -0800116from xml.etree import ElementTree
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800117
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800118import add_img_to_target_files
Daniel Normane9af70a2021-04-15 16:39:22 -0700119import apex_utils
Daniel Normandb8cacc2021-04-09 15:34:43 -0700120import build_image
Daniel Normanf0318252019-04-15 11:34:56 -0700121import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -0700122import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -0700123import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700124import img_from_target_files
Daniel Normanb8d52a22020-10-26 17:55:00 -0700125import find_shareduid_violation
Daniel Norman3b64ce12019-04-16 16:11:35 -0700126import ota_from_target_files
Daniel Normandb8cacc2021-04-09 15:34:43 -0700127import sparse_img
128import verity_utils
129
130from common import AddCareMapForAbOta, ExternalError, PARTITIONS_WITH_CARE_MAP
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800131
132logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -0700133
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800134OPTIONS = common.OPTIONS
Bill Peckhamcb848172020-04-03 12:50:47 -0700135# Always turn on verbose logging.
136OPTIONS.verbose = True
Daniel Normand5d70ea2019-06-05 15:13:43 -0700137OPTIONS.framework_target_files = None
138OPTIONS.framework_item_list = None
139OPTIONS.framework_misc_info_keys = None
140OPTIONS.vendor_target_files = None
141OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800142OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700143OPTIONS.output_dir = None
144OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700145OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700146OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700147OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700148# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700149OPTIONS.rebuild_recovery = False
Daniel Normanb0c75912020-09-24 14:30:21 -0700150# TODO(b/150582573): Remove this option.
151OPTIONS.allow_duplicate_apkapex_keys = False
Daniel Norman571e1822021-06-25 17:18:25 -0700152OPTIONS.vendor_otatools = None
153OPTIONS.rebuild_sepolicy = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800154OPTIONS.keep_tmp = False
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700155OPTIONS.framework_dexpreopt_config = None
156OPTIONS.framework_dexpreopt_tools = None
157OPTIONS.vendor_dexpreopt_config = None
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800158
Bill Peckham19c3feb2020-03-20 18:31:43 -0700159# In an item list (framework or vendor), we may see entries that select whole
160# partitions. Such an entry might look like this 'SYSTEM/*' (e.g., for the
161# system partition). The following regex matches this and extracts the
162# partition name.
163
164PARTITION_ITEM_PATTERN = re.compile(r'^([A-Z_]+)/\*$')
165
Bill Peckham5c7b0342020-04-03 15:36:23 -0700166# In apexkeys.txt or apkcerts.txt, we will find partition tags on each entry in
167# the file. We use these partition tags to filter the entries in those files
168# from the two different target files packages to produce a merged apexkeys.txt
169# or apkcerts.txt file. A partition tag (e.g., for the product partition) looks
170# like this: 'partition="product"'. We use the group syntax grab the value of
171# the tag. We use non-greedy matching in case there are other fields on the
172# same line.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700173
Bill Peckham5c7b0342020-04-03 15:36:23 -0700174PARTITION_TAG_PATTERN = re.compile(r'partition="(.*?)"')
Bill Peckham19c3feb2020-03-20 18:31:43 -0700175
176# The sorting algorithm for apexkeys.txt and apkcerts.txt does not include the
177# ".apex" or ".apk" suffix, so we use the following pattern to extract a key.
178
179MODULE_KEY_PATTERN = re.compile(r'name="(.+)\.(apex|apk)"')
180
Daniel Normand5d70ea2019-06-05 15:13:43 -0700181# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
182# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800183# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700184# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800185
Daniel Normand5d70ea2019-06-05 15:13:43 -0700186DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800187 'META/apkcerts.txt',
188 'META/filesystem_config.txt',
189 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800190 'META/update_engine_config.txt',
191 'PRODUCT/*',
192 'ROOT/*',
193 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700194)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800195
Daniel Normand5d70ea2019-06-05 15:13:43 -0700196# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700197# framework instance of META/misc_info.txt. The remaining keys should come
198# from the vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800199
Daniel Normand5d70ea2019-06-05 15:13:43 -0700200DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800201 'avb_system_hashtree_enable',
202 'avb_system_add_hashtree_footer_args',
203 'avb_system_key_path',
204 'avb_system_algorithm',
205 'avb_system_rollback_index_location',
206 'avb_product_hashtree_enable',
207 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900208 'avb_system_ext_hashtree_enable',
209 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800210 'system_root_image',
211 'root_dir',
212 'ab_update',
213 'default_system_dev_certificate',
214 'system_size',
Chris Gross203191b2020-05-30 02:39:12 +0000215 'building_system_image',
216 'building_system_ext_image',
217 'building_product_image',
Daniel Normanedf12472019-05-22 10:47:08 -0700218)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800219
Daniel Normand5d70ea2019-06-05 15:13:43 -0700220# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
221# vendor target files package as is, meaning these items will land in the output
222# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800223# files package.
224
Daniel Normand5d70ea2019-06-05 15:13:43 -0700225DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800226 'META/boot_filesystem_config.txt',
227 'META/otakeys.txt',
228 'META/releasetools.py',
229 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800230 'BOOT/*',
231 'DATA/*',
232 'ODM/*',
233 'OTA/android-info.txt',
234 'PREBUILT_IMAGES/*',
235 'RADIO/*',
236 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700237)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800238
Daniel Normanedf12472019-05-22 10:47:08 -0700239# The merge config lists should not attempt to extract items from both
240# builds for any of the following partitions. The partitions in
241# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700242# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700243
244SINGLE_BUILD_PARTITIONS = (
245 'BOOT/',
246 'DATA/',
247 'ODM/',
248 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900249 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700250 'RADIO/',
251 'RECOVERY/',
252 'ROOT/',
253 'SYSTEM/',
254 'SYSTEM_OTHER/',
255 'VENDOR/',
Yifan Hongcfb917a2020-05-07 14:58:20 -0700256 'VENDOR_DLKM/',
Yifan Hongf496f1b2020-07-15 16:52:59 -0700257 'ODM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700258)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800259
260
Chris Grossfabf50a2019-05-02 12:42:09 -0700261def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700262 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700263
Tao Bao2ad4b822019-06-27 16:52:12 -0700264 This function sorts the contents of the list or dict and then writes the
265 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700266
267 Args:
268 data: The list or dict to sort and write.
269 path: Path to the file to write the sorted values to. The file at path will
270 be overridden if it exists.
271 """
272 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700273 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700274 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
275 data, dict) else '{}\n'.format(entry)
276 output.write(out_str)
277
278
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800279def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700280 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800281
282 This function extracts from the specified target files zip archive into the
283 specified temporary directory, the items specified in the extract item list.
284
285 Args:
286 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800287 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700288 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800289 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800290 """
291
292 logger.info('extracting from %s', target_files)
293
294 # Filter the extract_item_list to remove any items that do not exist in the
295 # zip file. Otherwise, the extraction step will fail.
296
Daniel Norman4cc9df62019-07-18 10:11:07 -0700297 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800298 target_files_namelist = target_files_zipfile.namelist()
299
300 filtered_extract_item_list = []
301 for pattern in extract_item_list:
302 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
303 if not matching_namelist:
304 logger.warning('no match for %s', pattern)
305 else:
306 filtered_extract_item_list.append(pattern)
307
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800308 # Extract from target_files into target_files_temp_dir the
309 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800310
Daniel Normane5b134a2019-04-17 14:54:06 -0700311 common.UnzipToDir(target_files, target_files_temp_dir,
312 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800313
314
Daniel Normanfdb38812019-04-15 09:47:24 -0700315def copy_items(from_dir, to_dir, patterns):
316 """Similar to extract_items() except uses an input dir instead of zip."""
317 file_paths = []
318 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700319 file_paths.extend(
320 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
321 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700322
323 filtered_file_paths = set()
324 for pattern in patterns:
325 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
326
327 for file_path in filtered_file_paths:
328 original_file_path = os.path.join(from_dir, file_path)
329 copied_file_path = os.path.join(to_dir, file_path)
330 copied_file_dir = os.path.dirname(copied_file_path)
331 if not os.path.exists(copied_file_dir):
332 os.makedirs(copied_file_dir)
333 if os.path.islink(original_file_path):
334 os.symlink(os.readlink(original_file_path), copied_file_path)
335 else:
336 shutil.copyfile(original_file_path, copied_file_path)
337
338
Daniel Normand5d70ea2019-06-05 15:13:43 -0700339def validate_config_lists(framework_item_list, framework_misc_info_keys,
340 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700341 """Performs validations on the merge config lists.
342
343 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700344 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700345 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700346 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700347 instance of META/misc_info.txt. The remaining keys should come from the
348 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700349 vendor_item_list: The list of items to extract from the partial vendor
350 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700351
352 Returns:
353 False if a validation fails, otherwise true.
354 """
Daniel Normanedf12472019-05-22 10:47:08 -0700355 has_error = False
356
Daniel Normand5d70ea2019-06-05 15:13:43 -0700357 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
358 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700359
Daniel Normand5d70ea2019-06-05 15:13:43 -0700360 combined_item_set = set(framework_item_list)
361 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700362
363 # Check that the merge config lists are not missing any item specified
364 # by the default config lists.
365 difference = default_combined_item_set.difference(combined_item_set)
366 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700367 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700368 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700369 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700370 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700371 has_error = True
372
Daniel Normandbbf5a32020-10-22 16:03:32 -0700373 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700374 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700375 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
376 in_framework = (
377 any(item.startswith(partition) for item in framework_item_list) or
378 image_path in framework_item_list)
379 in_vendor = (
380 any(item.startswith(partition) for item in vendor_item_list) or
381 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700382 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700383 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700384 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900385 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700386 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700387 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700388
Daniel Normandb8cacc2021-04-09 15:34:43 -0700389 if ('dynamic_partition_list'
390 in framework_misc_info_keys) or ('super_partition_groups'
391 in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700392 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700393 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700394 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700395
Daniel Normanedf12472019-05-22 10:47:08 -0700396 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700397
398
Daniel Normand5d70ea2019-06-05 15:13:43 -0700399def process_ab_partitions_txt(framework_target_files_temp_dir,
400 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700401 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700402 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800403
Tao Bao2ad4b822019-06-27 16:52:12 -0700404 This function merges the contents of the META/ab_partitions.txt files from the
405 framework directory and the vendor directory, placing the merged result in the
406 output directory. The precondition in that the files are already extracted.
407 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700408 merged content. The format for each ab_partitions.txt is one partition name
409 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800410
411 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700412 framework_target_files_temp_dir: The name of a directory containing the
413 special items extracted from the framework target files package.
414 vendor_target_files_temp_dir: The name of a directory containing the special
415 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700416 output_target_files_temp_dir: The name of a directory that will be used to
417 create the output target files package after all the special cases are
418 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800419 """
420
Daniel Normand5d70ea2019-06-05 15:13:43 -0700421 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
422 'META', 'ab_partitions.txt')
423
424 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700425 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800426
Daniel Normand5d70ea2019-06-05 15:13:43 -0700427 with open(framework_ab_partitions_txt) as f:
428 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800429
Daniel Normand5d70ea2019-06-05 15:13:43 -0700430 with open(vendor_ab_partitions_txt) as f:
431 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800432
Daniel Normand5d70ea2019-06-05 15:13:43 -0700433 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800434
Daniel Normane5b134a2019-04-17 14:54:06 -0700435 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
436 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800437
Chris Grossfabf50a2019-05-02 12:42:09 -0700438 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800439
440
Daniel Normand5d70ea2019-06-05 15:13:43 -0700441def process_misc_info_txt(framework_target_files_temp_dir,
442 vendor_target_files_temp_dir,
443 output_target_files_temp_dir,
444 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700445 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800446
447 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700448 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800449 output directory. The precondition in that the files are already extracted.
450 The post condition is that the output META/misc_info.txt contains the merged
451 content.
452
453 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700454 framework_target_files_temp_dir: The name of a directory containing the
455 special items extracted from the framework target files package.
456 vendor_target_files_temp_dir: The name of a directory containing the special
457 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700458 output_target_files_temp_dir: The name of a directory that will be used to
459 create the output target files package after all the special cases are
460 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700461 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700462 instance of META/misc_info.txt. The remaining keys should come from the
463 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800464 """
465
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900466 misc_info_path = ['META', 'misc_info.txt']
467 framework_dict = common.LoadDictionaryFromFile(
468 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800469
Daniel Normand5d70ea2019-06-05 15:13:43 -0700470 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800471
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900472 merged_dict = common.LoadDictionaryFromFile(
473 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800474
Daniel Normand5d70ea2019-06-05 15:13:43 -0700475 # Replace certain values in merged_dict with values from
476 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800477
Daniel Normand5d70ea2019-06-05 15:13:43 -0700478 for key in framework_misc_info_keys:
479 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800480
Daniel Norman19b9fe92019-03-19 14:48:02 -0700481 # Merge misc info keys used for Dynamic Partitions.
Daniel Normandb8cacc2021-04-09 15:34:43 -0700482 if (merged_dict.get('use_dynamic_partitions')
483 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700484 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800485 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700486 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700487 # Ensure that add_img_to_target_files rebuilds super split images for
488 # devices that retrofit dynamic partitions. This flag may have been set to
489 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700490 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700491
Daniel Norman38888d32020-11-19 14:51:15 -0800492 # If AVB is enabled then ensure that we build vbmeta.img.
493 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
494 # skip building an incomplete vbmeta.img.
495 if merged_dict.get('avb_enable') == 'true':
496 merged_dict['avb_building_vbmeta_image'] = 'true'
497
Daniel Normand5d70ea2019-06-05 15:13:43 -0700498 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700499 # depending on which dictionary the key came from.
500 # Only the file basename is required because all selinux_fc properties are
501 # replaced with the full path to the file under META/ when misc_info.txt is
502 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700503 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700504 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700505 merged_dict[key] = 'vendor_file_contexts.bin'
506 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700507 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700508 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700509
Daniel Normane5b134a2019-04-17 14:54:06 -0700510 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
511 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700512 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800513
514
Daniel Normand5d70ea2019-06-05 15:13:43 -0700515def process_dynamic_partitions_info_txt(framework_target_files_dir,
516 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700517 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700518 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700519
520 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700521 files from the framework directory and the vendor directory, placing the
522 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700523
Daniel Normand5d70ea2019-06-05 15:13:43 -0700524 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700525 directory does not exist.
526
527 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700528 framework_target_files_dir: The name of a directory containing the special
529 items extracted from the framework target files package.
530 vendor_target_files_dir: The name of a directory containing the special
531 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700532 output_target_files_dir: The name of a directory that will be used to create
533 the output target files package after all the special cases are processed.
534 """
535
536 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700537 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700538 'dynamic_partitions_info.txt')):
539 return
540
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900541 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700542
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900543 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
544 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
545 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
546 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700547
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700548 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700549 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800550 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700551
552 output_dynamic_partitions_info_txt = os.path.join(
553 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700554 write_sorted_data(
555 data=merged_dynamic_partitions_dict,
556 path=output_dynamic_partitions_info_txt)
557
558
Bill Peckham19c3feb2020-03-20 18:31:43 -0700559def item_list_to_partition_set(item_list):
560 """Converts a target files item list to a partition set.
561
562 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
563 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
564 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
565 contents of a partition of the same name. Other items in the list, such as the
566 'OTA' example contain metadata. This function iterates such a list, returning
567 a set that contains the partition entries.
568
569 Args:
570 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700571
Bill Peckham19c3feb2020-03-20 18:31:43 -0700572 Returns:
573 A set of partitions extracted from the list of items.
574 """
575
576 partition_set = set()
577
578 for item in item_list:
579 match = PARTITION_ITEM_PATTERN.search(item.strip())
580 partition_tag = match.group(1).lower() if match else None
581
582 if partition_tag:
583 partition_set.add(partition_tag)
584
585 return partition_set
586
587
Daniel Normand5d70ea2019-06-05 15:13:43 -0700588def process_apex_keys_apk_certs_common(framework_target_files_dir,
589 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700590 output_target_files_dir,
591 framework_partition_set,
592 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700593 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700594
595 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700596 META/apkcerts.txt files from the framework directory and the vendor directory,
597 placing the merged result in the output directory. The precondition in that
598 the files are already extracted. The post condition is that the output
599 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700600
601 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700602 framework_target_files_dir: The name of a directory containing the special
603 items extracted from the framework target files package.
604 vendor_target_files_dir: The name of a directory containing the special
605 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700606 output_target_files_dir: The name of a directory that will be used to create
607 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700608 framework_partition_set: Partitions that are considered framework
609 partitions. Used to filter apexkeys.txt and apkcerts.txt.
610 vendor_partition_set: Partitions that are considered vendor partitions. Used
611 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700612 file_name: The name of the file to merge. One of apkcerts.txt or
613 apexkeys.txt.
614 """
615
616 def read_helper(d):
617 temp = {}
618 file_path = os.path.join(d, 'META', file_name)
619 with open(file_path) as f:
620 for line in f:
621 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700622 name = line.split()[0]
623 match = MODULE_KEY_PATTERN.search(name)
624 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700625 return temp
626
Daniel Normand5d70ea2019-06-05 15:13:43 -0700627 framework_dict = read_helper(framework_target_files_dir)
628 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700629 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700630
Bill Peckham19c3feb2020-03-20 18:31:43 -0700631 def filter_into_merged_dict(item_dict, partition_set):
632 for key, value in item_dict.items():
633 match = PARTITION_TAG_PATTERN.search(value)
634
635 if match is None:
636 raise ValueError('Entry missing partition tag: %s' % value)
637
638 partition_tag = match.group(1)
639
640 if partition_tag in partition_set:
641 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700642 if OPTIONS.allow_duplicate_apkapex_keys:
643 # TODO(b/150582573) Always raise on duplicates.
644 logger.warning('Duplicate key %s' % key)
645 continue
646 else:
647 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700648
649 merged_dict[key] = value
650
651 filter_into_merged_dict(framework_dict, framework_partition_set)
652 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700653
654 output_file = os.path.join(output_target_files_dir, 'META', file_name)
655
Bill Peckham19c3feb2020-03-20 18:31:43 -0700656 # The following code is similar to write_sorted_data, but different enough
657 # that we couldn't use that function. We need the output to be sorted by the
658 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
659 # allows the sort to be consistent with the framework/vendor input data and
660 # eases comparison of input data with merged data.
661 with open(output_file, 'w') as output:
662 for key in sorted(merged_dict.keys()):
663 out_str = merged_dict[key] + '\n'
664 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700665
666
Daniel Normand5d70ea2019-06-05 15:13:43 -0700667def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700668 output_target_files_dir):
669 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700670 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
671 'framework_file_contexts.bin')
672 if not os.path.exists(framework_fc_path):
673 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
674 'file_contexts.bin')
675 if not os.path.exists(framework_fc_path):
676 raise ValueError('Missing framework file_contexts.bin.')
677 shutil.copyfile(
678 framework_fc_path,
679 os.path.join(output_target_files_dir, 'META',
680 'framework_file_contexts.bin'))
681
682 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
683 'vendor_file_contexts.bin')
684 if not os.path.exists(vendor_fc_path):
685 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700686 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700687 if not os.path.exists(vendor_fc_path):
688 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700689 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700690 vendor_fc_path,
691 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700692
693
Daniel Norman571e1822021-06-25 17:18:25 -0700694def compile_split_sepolicy(product_out, partition_map):
Daniel Norman48603ff2021-02-22 15:15:24 -0800695 """Uses secilc to compile a split sepolicy file.
696
697 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
698
699 Args:
700 product_out: PRODUCT_OUT directory, containing partition directories.
701 partition_map: A map of partition name -> relative path within product_out.
Daniel Norman48603ff2021-02-22 15:15:24 -0800702
703 Returns:
704 A command list that can be executed to create the compiled sepolicy.
705 """
706
707 def get_file(partition, path):
708 if partition not in partition_map:
709 logger.warning('Cannot load SEPolicy files for missing partition %s',
710 partition)
711 return None
712 return os.path.join(product_out, partition_map[partition], path)
713
714 # Load the kernel sepolicy version from the FCM. This is normally provided
715 # directly to selinux.cpp as a build flag, but is also available in this file.
716 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
717 if not fcm_file or not os.path.exists(fcm_file):
718 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
719 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
720 'sepolicy/kernel-sepolicy-version').text
721
722 # Load the vendor's plat sepolicy version. This is the version used for
723 # locating sepolicy mapping files.
724 vendor_plat_version_file = get_file('vendor',
725 'etc/selinux/plat_sepolicy_vers.txt')
726 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000727 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800728 raise ExternalError('Missing required sepolicy file %s',
729 vendor_plat_version_file)
730 with open(vendor_plat_version_file) as f:
731 vendor_plat_version = f.read().strip()
732
733 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
734 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
735 cmd.extend(['-c', kernel_sepolicy_version])
Daniel Norman571e1822021-06-25 17:18:25 -0700736 cmd.extend(['-o', os.path.join(product_out, 'META/combined_sepolicy')])
Daniel Norman48603ff2021-02-22 15:15:24 -0800737 cmd.extend(['-f', '/dev/null'])
738
739 required_policy_files = (
740 ('system', 'etc/selinux/plat_sepolicy.cil'),
741 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
742 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
743 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
744 )
745 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
746 required_policy_files)):
747 if not policy or not os.path.exists(policy):
748 raise ExternalError('Missing required sepolicy file %s', policy)
749 cmd.append(policy)
750
751 optional_policy_files = (
752 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
753 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
754 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
755 ('product', 'etc/selinux/product_sepolicy.cil'),
756 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
757 ('odm', 'etc/selinux/odm_sepolicy.cil'),
758 )
759 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
760 optional_policy_files)):
761 if policy and os.path.exists(policy):
762 cmd.append(policy)
763
764 return cmd
765
766
Daniel Normane9af70a2021-04-15 16:39:22 -0700767def validate_merged_apex_info(output_target_files_dir, partitions):
768 """Validates the APEX files in the merged target files directory.
769
770 Checks the APEX files in all possible preinstalled APEX directories.
771 Depends on the <partition>/apex/* APEX files within partitions.
772
773 Args:
Daniel Norman571e1822021-06-25 17:18:25 -0700774 output_target_files_dir: Output directory containing merged partition
775 directories.
Daniel Normane9af70a2021-04-15 16:39:22 -0700776 partitions: A list of all the partitions in the output directory.
777
778 Raises:
779 RuntimeError: if apex_utils fails to parse any APEX file.
780 ExternalError: if the same APEX package is provided by multiple partitions.
781 """
782 apex_packages = set()
783
784 apex_partitions = ('system', 'system_ext', 'product', 'vendor')
785 for partition in filter(lambda p: p in apex_partitions, partitions):
786 apex_info = apex_utils.GetApexInfoFromTargetFiles(
787 output_target_files_dir, partition, compressed_only=False)
788 partition_apex_packages = set([info.package_name for info in apex_info])
789 duplicates = apex_packages.intersection(partition_apex_packages)
790 if duplicates:
791 raise ExternalError(
792 'Duplicate APEX packages found in multiple partitions: %s' %
793 ' '.join(duplicates))
794 apex_packages.update(partition_apex_packages)
795
796
Daniel Normandb8cacc2021-04-09 15:34:43 -0700797def generate_care_map(partitions, output_target_files_dir):
798 """Generates a merged META/care_map.pb file in the output target files dir.
799
800 Depends on the info dict from META/misc_info.txt, as well as built images
801 within IMAGES/.
802
803 Args:
804 partitions: A list of partitions to potentially include in the care map.
805 output_target_files_dir: The name of a directory that will be used to create
806 the output target files package after all the special cases are processed.
807 """
808 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir)
809 partition_image_map = {}
810 for partition in partitions:
811 image_path = os.path.join(output_target_files_dir, 'IMAGES',
812 '{}.img'.format(partition))
813 if os.path.exists(image_path):
814 partition_image_map[partition] = image_path
815 # Regenerated images should have their image_size property already set.
816 image_size_prop = '{}_image_size'.format(partition)
817 if image_size_prop not in OPTIONS.info_dict:
818 # Images copied directly from input target files packages will need
819 # their image sizes calculated.
820 partition_size = sparse_img.GetImagePartitionSize(image_path)
821 image_props = build_image.ImagePropFromGlobalDict(
822 OPTIONS.info_dict, partition)
823 verity_image_builder = verity_utils.CreateVerityImageBuilder(
824 image_props)
825 image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
826 OPTIONS.info_dict[image_size_prop] = image_size
827
828 AddCareMapForAbOta(
829 os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
830 PARTITIONS_WITH_CARE_MAP, partition_image_map)
831
832
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700833def process_special_cases(temp_dir, framework_meta, vendor_meta,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700834 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700835 framework_misc_info_keys, framework_partition_set,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700836 vendor_partition_set, framework_dexpreopt_tools,
837 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -0700838 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800839
840 Certain files in the output target files package require special-case
841 processing. This function performs all that special-case processing.
842
843 Args:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700844 temp_dir: Location containing an 'output' directory where target files have
845 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
846 framework_meta: The name of a directory containing the special items
847 extracted from the framework target files package.
848 vendor_meta: The name of a directory containing the special items
849 extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700850 output_target_files_temp_dir: The name of a directory that will be used to
851 create the output target files package after all the special cases are
852 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700853 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700854 instance of META/misc_info.txt. The remaining keys should come from the
855 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700856 framework_partition_set: Partitions that are considered framework
857 partitions. Used to filter apexkeys.txt and apkcerts.txt.
858 vendor_partition_set: Partitions that are considered vendor partitions. Used
859 to filter apexkeys.txt and apkcerts.txt.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700860
861 The following are only used if dexpreopt is applied:
862
863 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
864 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
865 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800866 """
867
Daniel Normand5d70ea2019-06-05 15:13:43 -0700868 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700869 process_ab_partitions_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700870 framework_target_files_temp_dir=framework_meta,
871 vendor_target_files_temp_dir=vendor_meta,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700872 output_target_files_temp_dir=output_target_files_temp_dir)
873
Daniel Norman72c626f2019-05-13 15:58:14 -0700874 copy_file_contexts(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700875 framework_target_files_dir=framework_meta,
876 vendor_target_files_dir=vendor_meta,
Daniel Norman72c626f2019-05-13 15:58:14 -0700877 output_target_files_dir=output_target_files_temp_dir)
878
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800879 process_misc_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700880 framework_target_files_temp_dir=framework_meta,
881 vendor_target_files_temp_dir=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800882 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700883 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800884
Daniel Normana61cde02019-05-03 14:19:13 -0700885 process_dynamic_partitions_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700886 framework_target_files_dir=framework_meta,
887 vendor_target_files_dir=vendor_meta,
Daniel Norman714bd122019-05-08 16:20:02 -0700888 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700889
Chris Grossfabf50a2019-05-02 12:42:09 -0700890 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700891 framework_target_files_dir=framework_meta,
892 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700893 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700894 framework_partition_set=framework_partition_set,
895 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700896 file_name='apkcerts.txt')
897
898 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700899 framework_target_files_dir=framework_meta,
900 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700901 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700902 framework_partition_set=framework_partition_set,
903 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700904 file_name='apexkeys.txt')
905
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700906 process_dexopt(
907 temp_dir=temp_dir,
908 framework_meta=framework_meta,
909 vendor_meta=vendor_meta,
910 output_target_files_temp_dir=output_target_files_temp_dir,
911 framework_dexpreopt_tools=framework_dexpreopt_tools,
912 framework_dexpreopt_config=framework_dexpreopt_config,
913 vendor_dexpreopt_config=vendor_dexpreopt_config)
914
915
916def process_dexopt(temp_dir, framework_meta, vendor_meta,
917 output_target_files_temp_dir,
918 framework_dexpreopt_tools, framework_dexpreopt_config,
919 vendor_dexpreopt_config):
920 """If needed, generates dexopt files for vendor apps.
921
922 Args:
923 temp_dir: Location containing an 'output' directory where target files have
924 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
925 framework_meta: The name of a directory containing the special items
926 extracted from the framework target files package.
927 vendor_meta: The name of a directory containing the special items extracted
928 from the vendor target files package.
929 output_target_files_temp_dir: The name of a directory that will be used to
930 create the output target files package after all the special cases are
931 processed.
932 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
933 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
934 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
935 """
936 # Load vendor and framework META/misc_info.txt.
937 misc_info_path = ['META', 'misc_info.txt']
938 vendor_misc_info_dict = common.LoadDictionaryFromFile(
939 os.path.join(vendor_meta, *misc_info_path))
940
941 if (vendor_misc_info_dict.get('building_with_vsdk') != 'true' or
942 framework_dexpreopt_tools is None or
943 framework_dexpreopt_config is None or
944 vendor_dexpreopt_config is None):
945 return
946
947 logger.info('applying dexpreopt')
948
949 # The directory structure to apply dexpreopt is:
950 #
951 # <temp_dir>/
952 # framework_meta/
953 # META/
954 # vendor_meta/
955 # META/
956 # output/
957 # SYSTEM/
958 # VENDOR/
959 # IMAGES/
960 # <other items extracted from system and vendor target files>
961 # tools/
962 # <contents of dexpreopt_tools.zip>
963 # system_config/
964 # <contents of system dexpreopt_config.zip>
965 # vendor_config/
966 # <contents of vendor dexpreopt_config.zip>
967 # system -> output/SYSTEM
968 # vendor -> output/VENDOR
969 # apex -> output/SYSTEM/apex (only for flattened APEX builds)
970 # apex/ (extracted updatable APEX)
971 # <apex 1>/
972 # ...
973 # <apex 2>/
974 # ...
975 # ...
976 # out/dex2oat_result/vendor/
977 # <app>
978 # oat/arm64/
979 # package.vdex
980 # package.odex
981 # <priv-app>
982 # oat/arm64/
983 # package.vdex
984 # package.odex
985 dexpreopt_tools_files_temp_dir = os.path.join(temp_dir, 'tools')
986 dexpreopt_framework_config_files_temp_dir = os.path.join(temp_dir, 'system_config')
987 dexpreopt_vendor_config_files_temp_dir = os.path.join(temp_dir, 'vendor_config')
988
989 extract_items(
990 target_files=OPTIONS.framework_dexpreopt_tools,
991 target_files_temp_dir=dexpreopt_tools_files_temp_dir,
992 extract_item_list=('*',))
993 extract_items(
994 target_files=OPTIONS.framework_dexpreopt_config,
995 target_files_temp_dir=dexpreopt_framework_config_files_temp_dir,
996 extract_item_list=('*',))
997 extract_items(
998 target_files=OPTIONS.vendor_dexpreopt_config,
999 target_files_temp_dir=dexpreopt_vendor_config_files_temp_dir,
1000 extract_item_list=('*',))
1001
1002 os.symlink(os.path.join(output_target_files_temp_dir, "SYSTEM"),
1003 os.path.join(temp_dir, "system"))
1004 os.symlink(os.path.join(output_target_files_temp_dir, "VENDOR"),
1005 os.path.join(temp_dir, "vendor"))
1006
1007 # The directory structure for flatteded APEXes is:
1008 #
1009 # SYSTEM
1010 # apex
1011 # <APEX name, e.g., com.android.wifi>
1012 # apex_manifest.pb
1013 # apex_pubkey
1014 # etc/
1015 # javalib/
1016 # lib/
1017 # lib64/
1018 # priv-app/
1019 #
1020 # The directory structure for updatable APEXes is:
1021 #
1022 # SYSTEM
1023 # apex
1024 # com.android.adbd.apex
1025 # com.android.appsearch.apex
1026 # com.android.art.apex
1027 # ...
1028 apex_root = os.path.join(output_target_files_temp_dir, "SYSTEM", "apex")
1029 framework_misc_info_dict = common.LoadDictionaryFromFile(
1030 os.path.join(framework_meta, *misc_info_path))
1031
1032 # Check for flattended versus updatable APEX.
1033 if framework_misc_info_dict.get('target_flatten_apex') == 'false':
1034 # Extract APEX.
1035 logging.info('extracting APEX')
1036
1037 apex_extract_root_dir = os.path.join(temp_dir, 'apex')
1038 os.makedirs(apex_extract_root_dir)
1039
1040 for apex in (glob.glob(os.path.join(apex_root, '*.apex')) +
1041 glob.glob(os.path.join(apex_root, '*.capex'))):
1042 logging.info(' apex: %s', apex)
1043 # deapexer is in the same directory as the merge_target_files binary extracted
1044 # from otatools.zip.
1045 apex_json_info = subprocess.check_output(['deapexer', 'info', apex])
1046 logging.info(' info: %s', apex_json_info)
1047 apex_info = json.loads(apex_json_info)
1048 apex_name = apex_info['name']
1049 logging.info(' name: %s', apex_name)
1050
1051 apex_extract_dir = os.path.join(apex_extract_root_dir, apex_name)
1052 os.makedirs(apex_extract_dir)
1053
1054 # deapexer uses debugfs_static, which is part of otatools.zip.
1055 command = [
1056 'deapexer',
1057 '--debugfs_path',
1058 'debugfs_static',
1059 'extract',
1060 apex,
1061 apex_extract_dir,
1062 ]
1063 logging.info(' running %s', command)
1064 subprocess.check_call(command)
1065 else:
1066 # Flattened APEXes don't need to be extracted since they have the necessary
1067 # directory structure.
1068 os.symlink(os.path.join(apex_root), os.path.join(temp_dir, 'apex'))
1069
1070 # Modify system config to point to the tools that have been extracted.
1071 # Absolute or .. paths are not allowed by the dexpreopt_gen tool in
1072 # dexpreopt_soong.config.
1073 dexpreopt_framework_soon_config = os.path.join(
1074 dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config')
1075 with open(dexpreopt_framework_soon_config, 'w') as f:
1076 dexpreopt_soong_config = {
1077 'Profman': 'tools/profman',
1078 'Dex2oat': 'tools/dex2oatd',
1079 'Aapt': 'tools/aapt2',
1080 'SoongZip': 'tools/soong_zip',
1081 'Zip2zip': 'tools/zip2zip',
1082 'ManifestCheck': 'tools/manifest_check',
1083 'ConstructContext': 'tools/construct_context',
1084 }
1085 json.dump(dexpreopt_soong_config, f)
1086
1087 # TODO(b/188179859): Make *dex location configurable to vendor or system_other.
1088 use_system_other_odex = False
1089
1090 if use_system_other_odex:
1091 dex_img = 'SYSTEM_OTHER'
1092 else:
1093 dex_img = 'VENDOR'
1094 # Open vendor_filesystem_config to append the items generated by dexopt.
1095 vendor_file_system_config = open(
1096 os.path.join(temp_dir, 'output', 'META', 'vendor_filesystem_config.txt'),
1097 'a')
1098
1099 # Dexpreopt vendor apps.
1100 dexpreopt_config_suffix = '_dexpreopt.config'
1101 for config in glob.glob(os.path.join(
1102 dexpreopt_vendor_config_files_temp_dir, '*' + dexpreopt_config_suffix)):
1103 app = os.path.basename(config)[:-len(dexpreopt_config_suffix)]
1104 logging.info('dexpreopt config: %s %s', config, app)
1105
1106 apk_dir = 'app'
1107 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1108 if not os.path.exists(apk_path):
1109 apk_dir = 'priv-app'
1110 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1111 if not os.path.exists(apk_path):
1112 logging.warning('skipping dexpreopt for %s, no apk found in vendor/app '
1113 'or vendor/priv-app', app)
1114 continue
1115
1116 # Generate dexpreopting script. Note 'out_dir' is not the output directory
1117 # where the script is generated, but the OUT_DIR at build time referenced
1118 # in the dexpreot config files, e.g., "out/.../core-oj.jar", so the tool knows
1119 # how to adjust the path.
1120 command = [
1121 os.path.join(dexpreopt_tools_files_temp_dir, 'dexpreopt_gen'),
1122 '-global',
1123 os.path.join(dexpreopt_framework_config_files_temp_dir, 'dexpreopt.config'),
1124 '-global_soong',
1125 os.path.join(
1126 dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config'),
1127 '-module',
1128 config,
1129 '-dexpreopt_script',
1130 'dexpreopt_app.sh',
1131 '-out_dir',
1132 'out',
1133 '-base_path',
1134 '.',
1135 '--uses_target_files',
1136 ]
1137
1138 # Run the command from temp_dir so all tool paths are its descendants.
1139 logging.info("running %s", command)
1140 subprocess.check_call(command, cwd = temp_dir)
1141
1142 # Call the generated script.
1143 command = ['sh', 'dexpreopt_app.sh', apk_path]
1144 logging.info("running %s", command)
1145 subprocess.check_call(command, cwd = temp_dir)
1146
1147 # Output files are in:
1148 #
1149 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.vdex
1150 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.odex
1151 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.vdex
1152 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.odex
1153 #
1154 # Copy the files to their destination. The structure of system_other is:
1155 #
1156 # system_other/
1157 # system-other-odex-marker
1158 # system/
1159 # app/
1160 # <app>/oat/arm64/
1161 # <app>.odex
1162 # <app>.vdex
1163 # ...
1164 # priv-app/
1165 # <app>/oat/arm64/
1166 # <app>.odex
1167 # <app>.vdex
1168 # ...
1169
1170 # TODO(b/188179859): Support for other architectures.
1171 arch = 'arm64'
1172
1173 dex_destination = os.path.join(temp_dir, 'output', dex_img, apk_dir, app, 'oat', arch)
1174 os.makedirs(dex_destination)
1175 dex2oat_path = os.path.join(
1176 temp_dir, 'out', 'dex2oat_result', 'vendor', apk_dir, app, 'oat', arch)
1177 shutil.copy(os.path.join(dex2oat_path, 'package.vdex'),
1178 os.path.join(dex_destination, app + '.vdex'))
1179 shutil.copy(os.path.join(dex2oat_path, 'package.odex'),
1180 os.path.join(dex_destination, app + '.odex'))
1181
1182 # Append entries to vendor_file_system_config.txt, such as:
1183 #
1184 # vendor/app/<app>/oat 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1185 # vendor/app/<app>/oat/arm64 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1186 # vendor/app/<app>/oat/arm64/<app>.odex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1187 # vendor/app/<app>/oat/arm64/<app>.vdex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1188 if not use_system_other_odex:
1189 vendor_app_prefix = 'vendor/' + apk_dir + '/' + app + '/oat'
1190 selabel = 'selabel=u:object_r:vendor_app_file:s0 capabilities=0x0'
1191 vendor_file_system_config.writelines([
1192 vendor_app_prefix + ' 0 2000 755 ' + selabel + '\n',
1193 vendor_app_prefix + '/' + arch + ' 0 2000 755 ' + selabel + '\n',
1194 vendor_app_prefix + '/' + arch + '/' + app + '.odex 0 0 644 ' + selabel + '\n',
1195 vendor_app_prefix + '/' + arch + '/' + app + '.vdex 0 0 644 ' + selabel + '\n',
1196 ])
1197
1198 if not use_system_other_odex:
1199 vendor_file_system_config.close()
1200 # Delete vendor.img so that it will be regenerated.
1201 # TODO(b/188179859): Rebuilding a vendor image in GRF mode (e.g., T(framework)
1202 # and S(vendor) may require logic similar to that in
1203 # rebuild_image_with_sepolicy.
1204 vendor_img = os.path.join(output_target_files_temp_dir, 'IMAGES', 'vendor.img')
1205 if os.path.exists(vendor_img):
1206 logging.info('Deleting %s', vendor_img)
1207 os.remove(vendor_img)
1208
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001209
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001210def create_merged_package(temp_dir, framework_target_files, framework_item_list,
1211 vendor_target_files, vendor_item_list,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001212 framework_misc_info_keys, rebuild_recovery,
1213 framework_dexpreopt_tools, framework_dexpreopt_config,
1214 vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001215 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001216
1217 Args:
1218 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -07001219 input target files packages, and also a scratch directory that we use for
1220 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001221 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001222 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001223 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001224 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -07001225 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001226 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001227 vendor_target_files: The name of the zip archive containing the vendor
1228 partial target files package.
1229 vendor_item_list: The list of items to extract from the partial vendor
1230 target files package as is, meaning these items will land in the output
1231 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -07001232 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001233 framework_misc_info_keys: A list of keys to obtain from the framework
1234 instance of META/misc_info.txt. The remaining keys should come from the
1235 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -07001236 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -07001237 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001238
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001239 The following are only used if dexpreopt is applied:
1240
1241 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1242 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1243 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
1244
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001245 Returns:
1246 Path to merged package under temp directory.
1247 """
Daniel Normandbbf5a32020-10-22 16:03:32 -07001248 # Extract "as is" items from the input framework and vendor partial target
1249 # files packages directly into the output temporary directory, since these items
1250 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001251
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001252 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -08001253 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001254 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001255 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001256 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -08001257 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001258 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001259 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001260 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001261
Daniel Normandbbf5a32020-10-22 16:03:32 -07001262 # Perform special case processing on META/* items.
1263 # After this function completes successfully, all the files we need to create
1264 # the output target files package are in place.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001265 framework_meta = os.path.join(temp_dir, 'framework_meta')
1266 vendor_meta = os.path.join(temp_dir, 'vendor_meta')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001267 extract_items(
1268 target_files=framework_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001269 target_files_temp_dir=framework_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001270 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001271 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001272 target_files=vendor_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001273 target_files_temp_dir=vendor_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001274 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001275 process_special_cases(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001276 temp_dir=temp_dir,
1277 framework_meta=framework_meta,
1278 vendor_meta=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001279 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -07001280 framework_misc_info_keys=framework_misc_info_keys,
1281 framework_partition_set=item_list_to_partition_set(framework_item_list),
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001282 vendor_partition_set=item_list_to_partition_set(vendor_item_list),
1283 framework_dexpreopt_tools=framework_dexpreopt_tools,
1284 framework_dexpreopt_config=framework_dexpreopt_config,
1285 vendor_dexpreopt_config=vendor_dexpreopt_config)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001286
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001287 return output_target_files_temp_dir
1288
1289
1290def generate_images(target_files_dir, rebuild_recovery):
1291 """Generate images from target files.
1292
1293 This function takes merged output temporary directory and create images
1294 from it.
1295
1296 Args:
1297 target_files_dir: Path to merged temp directory.
1298 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1299 devices and write it to the system image.
1300 """
1301
1302 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001303
Daniel Normandbbf5a32020-10-22 16:03:32 -07001304 add_img_args = [
1305 '--verbose',
1306 '--add_missing',
1307 ]
Bill Peckhame868aec2019-09-17 17:06:47 -07001308 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -07001309 if rebuild_recovery:
1310 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001311 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001312
1313 add_img_to_target_files.main(add_img_args)
1314
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001315
Daniel Norman571e1822021-06-25 17:18:25 -07001316def rebuild_image_with_sepolicy(target_files_dir,
1317 vendor_otatools=None,
1318 vendor_target_files=None):
1319 """Rebuilds odm.img or vendor.img to include merged sepolicy files.
1320
1321 If odm is present then odm is preferred -- otherwise vendor is used.
1322
1323 Args:
1324 target_files_dir: Path to the extracted merged target-files package.
1325 vendor_otatools: If not None, path to an otatools.zip from the vendor build
1326 that is used when recompiling the image.
1327 vendor_target_files: Expected if vendor_otatools is not None. Path to the
1328 vendor target-files zip.
1329 """
1330 partition = 'vendor'
1331 if os.path.exists(os.path.join(target_files_dir, 'ODM')) or os.path.exists(
1332 os.path.join(target_files_dir, 'IMAGES/odm.img')):
1333 partition = 'odm'
1334 partition_img = '{}.img'.format(partition)
1335
1336 logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
1337
1338 # Copy the combined SEPolicy file and framework hashes to the image that is
1339 # being rebuilt.
1340 def copy_selinux_file(input_path, output_filename):
Po Hu0e4403e2021-07-06 17:05:56 +08001341 input_filename = os.path.join(target_files_dir, input_path)
1342 if not os.path.exists(input_filename):
1343 input_filename = input_filename.replace('SYSTEM_EXT/', 'SYSTEM/system_ext/') \
1344 .replace('PRODUCT/', 'SYSTEM/product/')
1345 if not os.path.exists(input_filename):
1346 logger.info('Skipping copy_selinux_file for %s', input_filename)
1347 return
Daniel Norman571e1822021-06-25 17:18:25 -07001348 shutil.copy(
Po Hu0e4403e2021-07-06 17:05:56 +08001349 input_filename,
Daniel Norman571e1822021-06-25 17:18:25 -07001350 os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
1351 output_filename))
1352
1353 copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy')
1354 copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256',
1355 'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256')
1356 copy_selinux_file(
1357 'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256',
1358 'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256')
1359 copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256',
1360 'precompiled_sepolicy.product_sepolicy_and_mapping.sha256')
1361
1362 if not vendor_otatools:
1363 # Remove the partition from the merged target-files archive. It will be
1364 # rebuilt later automatically by generate_images().
1365 os.remove(os.path.join(target_files_dir, 'IMAGES', partition_img))
1366 else:
1367 # TODO(b/192253131): Remove the need for vendor_otatools by fixing
1368 # backwards-compatibility issues when compiling images on R from S+.
1369 if not vendor_target_files:
1370 raise ValueError(
1371 'Expected vendor_target_files if vendor_otatools is not None.')
1372 logger.info(
1373 '%s recompilation will be performed using the vendor otatools.zip',
1374 partition_img)
1375
1376 # Unzip the vendor build's otatools.zip and target-files archive.
1377 vendor_otatools_dir = common.MakeTempDir(
1378 prefix='merge_target_files_vendor_otatools_')
1379 vendor_target_files_dir = common.MakeTempDir(
1380 prefix='merge_target_files_vendor_target_files_')
1381 common.UnzipToDir(vendor_otatools, vendor_otatools_dir)
1382 common.UnzipToDir(vendor_target_files, vendor_target_files_dir)
1383
1384 # Copy the partition contents from the merged target-files archive to the
1385 # vendor target-files archive.
1386 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
1387 shutil.copytree(
1388 os.path.join(target_files_dir, partition.upper()),
Po Hu0e4403e2021-07-06 17:05:56 +08001389 os.path.join(vendor_target_files_dir, partition.upper()),
1390 symlinks=True)
Daniel Norman571e1822021-06-25 17:18:25 -07001391
1392 # Delete then rebuild the partition.
1393 os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
1394 rebuild_partition_command = [
1395 os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
1396 '--verbose',
1397 '--add_missing',
1398 vendor_target_files_dir,
1399 ]
1400 logger.info('Recompiling %s: %s', partition_img,
1401 ' '.join(rebuild_partition_command))
1402 common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
1403
1404 # Move the newly-created image to the merged target files dir.
Po Hu0e4403e2021-07-06 17:05:56 +08001405 if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')):
1406 os.makedirs(os.path.join(target_files_dir, 'IMAGES'))
Daniel Norman571e1822021-06-25 17:18:25 -07001407 shutil.move(
1408 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
1409 os.path.join(target_files_dir, 'IMAGES', partition_img))
1410
1411
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001412def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -07001413 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001414
1415 Args:
1416 target_dir: Path to the target file package which contains misc_info.txt for
1417 detailed information for super image.
1418 output_super_empty: If provided, copies a super_empty.img file from the
1419 target files package to this path.
1420 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001421 # Create super_empty.img using the merged misc_info.txt.
1422
Daniel Norman4cc9df62019-07-18 10:11:07 -07001423 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001424
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +09001425 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
1426 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001427
1428 if use_dynamic_partitions != 'true' and output_super_empty:
1429 raise ValueError(
1430 'Building super_empty.img requires use_dynamic_partitions=true.')
1431 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001432 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001433 build_super_image_args = [
1434 misc_info_txt,
1435 super_empty_img,
1436 ]
1437 build_super_image.main(build_super_image_args)
1438
1439 # Copy super_empty.img to the user-provided output_super_empty location.
1440 if output_super_empty:
1441 shutil.copyfile(super_empty_img, output_super_empty)
1442
Daniel Normanb8a2f9d2019-04-24 12:55:51 -07001443
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001444def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -07001445 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001446
1447 Args:
1448 output_file: The name of the zip archive target files package.
1449 source_dir: The target directory contains package to be archived.
1450 temp_dir: Path to temporary directory for any intermediate files.
1451 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001452 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001453 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001454 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001455
Daniel Normandbbf5a32020-10-22 16:03:32 -07001456 def files_from_path(target_path, extra_args=None):
1457 """Gets files under the given path and return a sorted list."""
1458 find_command = ['find', target_path] + (extra_args or [])
1459 find_process = common.Run(
1460 find_command, stdout=subprocess.PIPE, verbose=False)
1461 return common.RunAndCheckOutput(['sort'],
1462 stdin=find_process.stdout,
1463 verbose=False)
1464
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001465 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001466 other_content = files_from_path(
1467 source_dir,
1468 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001469
Tao Bao2ad4b822019-06-27 16:52:12 -07001470 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001471 f.write(meta_content)
1472 f.write(other_content)
1473
1474 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001475 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001476 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001477 '-o',
1478 output_zip,
1479 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001480 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001481 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001482 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001483 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001484
1485 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001486 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001487 logger.info('finished creating %s', output_file)
1488
1489 return output_zip
1490
1491
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001492def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1493 framework_misc_info_keys, vendor_target_files,
1494 vendor_item_list, output_target_files, output_dir,
1495 output_item_list, output_ota, output_img,
Daniel Norman571e1822021-06-25 17:18:25 -07001496 output_super_empty, rebuild_recovery, vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001497 rebuild_sepolicy, framework_dexpreopt_tools,
1498 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001499 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001500
1501 This function takes framework and vendor target files packages as input,
1502 performs various file extractions, special case processing, and finally
1503 creates a merged zip archive as output.
1504
1505 Args:
1506 temp_dir: The name of a directory we use when we extract items from the
1507 input target files packages, and also a scratch directory that we use for
1508 temporary files.
1509 framework_target_files: The name of the zip archive containing the framework
1510 partial target files package.
1511 framework_item_list: The list of items to extract from the partial framework
1512 target files package as is, meaning these items will land in the output
1513 target files package exactly as they appear in the input partial framework
1514 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001515 framework_misc_info_keys: A list of keys to obtain from the framework
1516 instance of META/misc_info.txt. The remaining keys should come from the
1517 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001518 vendor_target_files: The name of the zip archive containing the vendor
1519 partial target files package.
1520 vendor_item_list: The list of items to extract from the partial vendor
1521 target files package as is, meaning these items will land in the output
1522 target files package exactly as they appear in the input partial vendor
1523 target files package.
1524 output_target_files: The name of the output zip archive target files package
1525 created by merging framework and vendor.
1526 output_dir: The destination directory for saving merged files.
1527 output_item_list: The list of items to copy into the output_dir.
1528 output_ota: The name of the output zip archive ota package.
1529 output_img: The name of the output zip archive img package.
1530 output_super_empty: If provided, creates a super_empty.img file from the
1531 merged target files package and saves it at this path.
1532 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1533 devices and write it to the system image.
Daniel Norman571e1822021-06-25 17:18:25 -07001534 vendor_otatools: Path to an otatools zip used for recompiling vendor images.
1535 rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
1536 vendor.img using a merged precompiled_sepolicy file.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001537
1538 The following are only used if dexpreopt is applied:
1539
1540 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1541 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1542 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001543 """
1544
1545 logger.info('starting: merge framework %s and vendor %s into output %s',
1546 framework_target_files, vendor_target_files, output_target_files)
1547
1548 output_target_files_temp_dir = create_merged_package(
1549 temp_dir, framework_target_files, framework_item_list,
1550 vendor_target_files, vendor_item_list, framework_misc_info_keys,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001551 rebuild_recovery, framework_dexpreopt_tools, framework_dexpreopt_config,
1552 vendor_dexpreopt_config)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001553
Yifan Hongade0d3f2019-08-21 16:37:11 -07001554 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001555 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001556
Daniel Norman21c34f72020-11-11 17:25:50 -08001557 partition_map = common.PartitionMapFromTargetFiles(
1558 output_target_files_temp_dir)
1559
Daniel Normand3351562020-10-29 12:33:11 -07001560 # Generate and check for cross-partition violations of sharedUserId
1561 # values in APKs. This requires the input target-files packages to contain
1562 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001563 shareduid_violation_modules = os.path.join(
1564 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1565 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001566 violation = find_shareduid_violation.FindShareduidViolation(
1567 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001568
1569 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001570 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001571
1572 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001573 framework_partitions = item_list_to_partition_set(framework_item_list)
1574 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001575 shareduid_errors = common.SharedUidPartitionViolations(
1576 json.loads(violation), [framework_partitions, vendor_partitions])
1577 if shareduid_errors:
1578 for error in shareduid_errors:
1579 logger.error(error)
1580 raise ValueError('sharedUserId APK error. See %s' %
1581 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001582
Daniel Norman48603ff2021-02-22 15:15:24 -08001583 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001584 filtered_partitions = {
1585 partition: path
1586 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001587 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1588 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001589
1590 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001591 common.RunHostInitVerifier(
1592 product_out=output_target_files_temp_dir,
1593 partition_map=filtered_partitions)
1594
Daniel Norman48603ff2021-02-22 15:15:24 -08001595 # Check that the split sepolicy from the multiple builds can compile.
Daniel Norman571e1822021-06-25 17:18:25 -07001596 split_sepolicy_cmd = compile_split_sepolicy(output_target_files_temp_dir,
1597 filtered_partitions)
Daniel Norman48603ff2021-02-22 15:15:24 -08001598 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1599 common.RunAndCheckOutput(split_sepolicy_cmd)
Daniel Norman571e1822021-06-25 17:18:25 -07001600 # Include the compiled policy in an image if requested.
1601 if rebuild_sepolicy:
1602 rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
1603 vendor_target_files)
Daniel Norman48603ff2021-02-22 15:15:24 -08001604
Daniel Normane9af70a2021-04-15 16:39:22 -07001605 # Run validation checks on the pre-installed APEX files.
1606 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
1607
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001608 generate_images(output_target_files_temp_dir, rebuild_recovery)
1609
1610 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1611
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001612 # Finally, create the output target files zip archive and/or copy the
1613 # output items to the output target files directory.
1614
1615 if output_dir:
1616 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1617
1618 if not output_target_files:
1619 return
1620
Iavor-Valentin Iftimeb837b712022-01-27 16:29:37 +00001621 # Create the merged META/care_map.pb if A/B update
1622 if 'ab_update' in framework_misc_info_keys:
1623 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
Daniel Normandb8cacc2021-04-09 15:34:43 -07001624
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001625 output_zip = create_target_files_archive(output_target_files,
1626 output_target_files_temp_dir,
1627 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001628
Daniel Norman74eb74b2019-09-18 14:01:48 -07001629 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001630 if output_img:
1631 img_from_target_files.main([output_zip, output_img])
1632
Daniel Norman3b64ce12019-04-16 16:11:35 -07001633 # Create the OTA package from the merged target files package.
1634
1635 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001636 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001637
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001638
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001639def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001640 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001641
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001642 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001643 directory. It also cleans up the temporary directory.
1644
1645 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001646 func: The function to call. Should accept one parameter, the path to the
1647 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001648 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001649 """
1650
1651 # Create a temporary directory. This will serve as the parent of directories
1652 # we use when we extract items from the input target files packages, and also
1653 # a scratch directory that we use for temporary files.
1654
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001655 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1656
1657 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001658 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001659 finally:
1660 if keep_tmp:
1661 logger.info('keeping %s', temp_dir)
1662 else:
1663 common.Cleanup()
1664
1665
1666def main():
1667 """The main function.
1668
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001669 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001670 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001671 """
1672
1673 common.InitLogging()
1674
Bill Peckhamf753e152019-02-19 18:02:46 -08001675 def option_handler(o, a):
1676 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001677 logger.warning(
1678 '--system-target-files has been renamed to --framework-target-files')
1679 OPTIONS.framework_target_files = a
1680 elif o == '--framework-target-files':
1681 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001682 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001683 logger.warning(
1684 '--system-item-list has been renamed to --framework-item-list')
1685 OPTIONS.framework_item_list = a
1686 elif o == '--framework-item-list':
1687 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001688 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001689 logger.warning('--system-misc-info-keys has been renamed to '
1690 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001691 OPTIONS.framework_misc_info_keys = a
1692 elif o == '--framework-misc-info-keys':
1693 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001694 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001695 logger.warning(
1696 '--other-target-files has been renamed to --vendor-target-files')
1697 OPTIONS.vendor_target_files = a
1698 elif o == '--vendor-target-files':
1699 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001700 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001701 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001702 OPTIONS.vendor_item_list = a
1703 elif o == '--vendor-item-list':
1704 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001705 elif o == '--output-target-files':
1706 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001707 elif o == '--output-dir':
1708 OPTIONS.output_dir = a
1709 elif o == '--output-item-list':
1710 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001711 elif o == '--output-ota':
1712 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001713 elif o == '--output-img':
1714 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001715 elif o == '--output-super-empty':
1716 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001717 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001718 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001719 elif o == '--allow-duplicate-apkapex-keys':
1720 OPTIONS.allow_duplicate_apkapex_keys = True
Daniel Norman571e1822021-06-25 17:18:25 -07001721 elif o == '--vendor-otatools':
1722 OPTIONS.vendor_otatools = a
1723 elif o == '--rebuild-sepolicy':
1724 OPTIONS.rebuild_sepolicy = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001725 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001726 OPTIONS.keep_tmp = True
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001727 elif o == '--framework-dexpreopt-config':
1728 OPTIONS.framework_dexpreopt_config = a
1729 elif o == '--framework-dexpreopt-tools':
1730 OPTIONS.framework_dexpreopt_tools = a
1731 elif o == '--vendor-dexpreopt-config':
1732 OPTIONS.vendor_dexpreopt_config = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001733 else:
1734 return False
1735 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001736
Bill Peckhamf753e152019-02-19 18:02:46 -08001737 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001738 sys.argv[1:],
1739 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001740 extra_long_opts=[
1741 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001742 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001743 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001744 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001745 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001746 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001747 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001748 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001749 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001750 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001751 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001752 'output-dir=',
1753 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001754 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001755 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001756 'output-super-empty=',
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001757 'framework-dexpreopt-config=',
1758 'framework-dexpreopt-tools=',
1759 'vendor-dexpreopt-config=',
Daniel Normana4911da2019-03-15 14:36:21 -07001760 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001761 'allow-duplicate-apkapex-keys',
Daniel Norman571e1822021-06-25 17:18:25 -07001762 'vendor-otatools=',
1763 'rebuild-sepolicy',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001764 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001765 ],
1766 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001767
Tao Bao2ad4b822019-06-27 16:52:12 -07001768 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001769 if (args or OPTIONS.framework_target_files is None or
1770 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001771 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001772 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001773 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001774 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001775
Daniel Normand5d70ea2019-06-05 15:13:43 -07001776 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001777 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001778 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001779 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001780
Daniel Normand5d70ea2019-06-05 15:13:43 -07001781 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001782 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001783 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001784 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001785 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001786
Daniel Normand5d70ea2019-06-05 15:13:43 -07001787 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001788 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001789 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001790 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001791
Daniel Normanfdb38812019-04-15 09:47:24 -07001792 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001793 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001794 else:
1795 output_item_list = None
1796
Daniel Normane5964522019-03-19 10:32:03 -07001797 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001798 framework_item_list=framework_item_list,
1799 framework_misc_info_keys=framework_misc_info_keys,
1800 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001801 sys.exit(1)
1802
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001803 call_func_with_temp_dir(
1804 lambda temp_dir: merge_target_files(
1805 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001806 framework_target_files=OPTIONS.framework_target_files,
1807 framework_item_list=framework_item_list,
1808 framework_misc_info_keys=framework_misc_info_keys,
1809 vendor_target_files=OPTIONS.vendor_target_files,
1810 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001811 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001812 output_dir=OPTIONS.output_dir,
1813 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001814 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001815 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001816 output_super_empty=OPTIONS.output_super_empty,
Daniel Norman571e1822021-06-25 17:18:25 -07001817 rebuild_recovery=OPTIONS.rebuild_recovery,
1818 vendor_otatools=OPTIONS.vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001819 rebuild_sepolicy=OPTIONS.rebuild_sepolicy,
1820 framework_dexpreopt_tools=OPTIONS.framework_dexpreopt_tools,
1821 framework_dexpreopt_config=OPTIONS.framework_dexpreopt_config,
1822 vendor_dexpreopt_config=OPTIONS.vendor_dexpreopt_config), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001823
1824
1825if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001826 main()