blob: da5e93fb492a5ac681f44b28f69bda2560b2267a [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/',
Ramji Jiyani13a41372022-01-27 07:05:08 +0000258 'SYSTEM_DLKM/',
Daniel Normanedf12472019-05-22 10:47:08 -0700259)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800260
261
Chris Grossfabf50a2019-05-02 12:42:09 -0700262def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700263 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700264
Tao Bao2ad4b822019-06-27 16:52:12 -0700265 This function sorts the contents of the list or dict and then writes the
266 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700267
268 Args:
269 data: The list or dict to sort and write.
270 path: Path to the file to write the sorted values to. The file at path will
271 be overridden if it exists.
272 """
273 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700274 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700275 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
276 data, dict) else '{}\n'.format(entry)
277 output.write(out_str)
278
279
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800280def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700281 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800282
283 This function extracts from the specified target files zip archive into the
284 specified temporary directory, the items specified in the extract item list.
285
286 Args:
287 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800288 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700289 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800290 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800291 """
292
293 logger.info('extracting from %s', target_files)
294
295 # Filter the extract_item_list to remove any items that do not exist in the
296 # zip file. Otherwise, the extraction step will fail.
297
Daniel Norman4cc9df62019-07-18 10:11:07 -0700298 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800299 target_files_namelist = target_files_zipfile.namelist()
300
301 filtered_extract_item_list = []
302 for pattern in extract_item_list:
303 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
304 if not matching_namelist:
305 logger.warning('no match for %s', pattern)
306 else:
307 filtered_extract_item_list.append(pattern)
308
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800309 # Extract from target_files into target_files_temp_dir the
310 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800311
Daniel Normane5b134a2019-04-17 14:54:06 -0700312 common.UnzipToDir(target_files, target_files_temp_dir,
313 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800314
315
Daniel Normanfdb38812019-04-15 09:47:24 -0700316def copy_items(from_dir, to_dir, patterns):
317 """Similar to extract_items() except uses an input dir instead of zip."""
318 file_paths = []
319 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700320 file_paths.extend(
321 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
322 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700323
324 filtered_file_paths = set()
325 for pattern in patterns:
326 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
327
328 for file_path in filtered_file_paths:
329 original_file_path = os.path.join(from_dir, file_path)
330 copied_file_path = os.path.join(to_dir, file_path)
331 copied_file_dir = os.path.dirname(copied_file_path)
332 if not os.path.exists(copied_file_dir):
333 os.makedirs(copied_file_dir)
334 if os.path.islink(original_file_path):
335 os.symlink(os.readlink(original_file_path), copied_file_path)
336 else:
337 shutil.copyfile(original_file_path, copied_file_path)
338
339
Daniel Normand5d70ea2019-06-05 15:13:43 -0700340def validate_config_lists(framework_item_list, framework_misc_info_keys,
341 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700342 """Performs validations on the merge config lists.
343
344 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700345 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700346 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700347 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700348 instance of META/misc_info.txt. The remaining keys should come from the
349 vendor instance.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700350 vendor_item_list: The list of items to extract from the partial vendor
351 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700352
353 Returns:
354 False if a validation fails, otherwise true.
355 """
Daniel Normanedf12472019-05-22 10:47:08 -0700356 has_error = False
357
Daniel Normand5d70ea2019-06-05 15:13:43 -0700358 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
359 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700360
Daniel Normand5d70ea2019-06-05 15:13:43 -0700361 combined_item_set = set(framework_item_list)
362 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700363
364 # Check that the merge config lists are not missing any item specified
365 # by the default config lists.
366 difference = default_combined_item_set.difference(combined_item_set)
367 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700368 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700369 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700370 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700371 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700372 has_error = True
373
Daniel Normandbbf5a32020-10-22 16:03:32 -0700374 # Check that partitions only come from one input.
Daniel Normanedf12472019-05-22 10:47:08 -0700375 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normandbbf5a32020-10-22 16:03:32 -0700376 image_path = 'IMAGES/{}.img'.format(partition.lower().replace('/', ''))
377 in_framework = (
378 any(item.startswith(partition) for item in framework_item_list) or
379 image_path in framework_item_list)
380 in_vendor = (
381 any(item.startswith(partition) for item in vendor_item_list) or
382 image_path in vendor_item_list)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700383 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700384 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700385 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900386 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700387 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700388 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700389
Daniel Normandb8cacc2021-04-09 15:34:43 -0700390 if ('dynamic_partition_list'
391 in framework_misc_info_keys) or ('super_partition_groups'
392 in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700393 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700394 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700395 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700396
Daniel Normanedf12472019-05-22 10:47:08 -0700397 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700398
399
Daniel Normand5d70ea2019-06-05 15:13:43 -0700400def process_ab_partitions_txt(framework_target_files_temp_dir,
401 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700402 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700403 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800404
Tao Bao2ad4b822019-06-27 16:52:12 -0700405 This function merges the contents of the META/ab_partitions.txt files from the
406 framework directory and the vendor directory, placing the merged result in the
407 output directory. The precondition in that the files are already extracted.
408 The post condition is that the output META/ab_partitions.txt contains the
Daniel Normandbbf5a32020-10-22 16:03:32 -0700409 merged content. The format for each ab_partitions.txt is one partition name
410 per line. The output file contains the union of the partition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800411
412 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700413 framework_target_files_temp_dir: The name of a directory containing the
414 special items extracted from the framework target files package.
415 vendor_target_files_temp_dir: The name of a directory containing the special
416 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700417 output_target_files_temp_dir: The name of a directory that will be used to
418 create the output target files package after all the special cases are
419 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800420 """
421
Daniel Normand5d70ea2019-06-05 15:13:43 -0700422 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
423 'META', 'ab_partitions.txt')
424
425 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700426 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800427
Daniel Normand5d70ea2019-06-05 15:13:43 -0700428 with open(framework_ab_partitions_txt) as f:
429 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800430
Daniel Normand5d70ea2019-06-05 15:13:43 -0700431 with open(vendor_ab_partitions_txt) as f:
432 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800433
Daniel Normand5d70ea2019-06-05 15:13:43 -0700434 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800435
Daniel Normane5b134a2019-04-17 14:54:06 -0700436 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
437 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800438
Chris Grossfabf50a2019-05-02 12:42:09 -0700439 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800440
441
Daniel Normand5d70ea2019-06-05 15:13:43 -0700442def process_misc_info_txt(framework_target_files_temp_dir,
443 vendor_target_files_temp_dir,
444 output_target_files_temp_dir,
445 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700446 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800447
448 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700449 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800450 output directory. The precondition in that the files are already extracted.
451 The post condition is that the output META/misc_info.txt contains the merged
452 content.
453
454 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700455 framework_target_files_temp_dir: The name of a directory containing the
456 special items extracted from the framework target files package.
457 vendor_target_files_temp_dir: The name of a directory containing the special
458 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700459 output_target_files_temp_dir: The name of a directory that will be used to
460 create the output target files package after all the special cases are
461 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700462 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700463 instance of META/misc_info.txt. The remaining keys should come from the
464 vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800465 """
466
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900467 misc_info_path = ['META', 'misc_info.txt']
468 framework_dict = common.LoadDictionaryFromFile(
469 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800470
Daniel Normand5d70ea2019-06-05 15:13:43 -0700471 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800472
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900473 merged_dict = common.LoadDictionaryFromFile(
474 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800475
Daniel Normand5d70ea2019-06-05 15:13:43 -0700476 # Replace certain values in merged_dict with values from
477 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800478
Daniel Normand5d70ea2019-06-05 15:13:43 -0700479 for key in framework_misc_info_keys:
480 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800481
Daniel Norman19b9fe92019-03-19 14:48:02 -0700482 # Merge misc info keys used for Dynamic Partitions.
Daniel Normandb8cacc2021-04-09 15:34:43 -0700483 if (merged_dict.get('use_dynamic_partitions')
484 == 'true') and (framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700485 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Norman55417142019-11-25 16:04:36 -0800486 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700487 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700488 # Ensure that add_img_to_target_files rebuilds super split images for
489 # devices that retrofit dynamic partitions. This flag may have been set to
490 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700491 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700492
Daniel Norman38888d32020-11-19 14:51:15 -0800493 # If AVB is enabled then ensure that we build vbmeta.img.
494 # Partial builds with AVB enabled may set PRODUCT_BUILD_VBMETA_IMAGE=false to
495 # skip building an incomplete vbmeta.img.
496 if merged_dict.get('avb_enable') == 'true':
497 merged_dict['avb_building_vbmeta_image'] = 'true'
498
Daniel Normand5d70ea2019-06-05 15:13:43 -0700499 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700500 # depending on which dictionary the key came from.
501 # Only the file basename is required because all selinux_fc properties are
502 # replaced with the full path to the file under META/ when misc_info.txt is
503 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700504 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700505 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700506 merged_dict[key] = 'vendor_file_contexts.bin'
507 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700508 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700509 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700510
Daniel Normane5b134a2019-04-17 14:54:06 -0700511 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
512 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700513 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800514
515
Daniel Normand5d70ea2019-06-05 15:13:43 -0700516def process_dynamic_partitions_info_txt(framework_target_files_dir,
517 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700518 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700519 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700520
521 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700522 files from the framework directory and the vendor directory, placing the
523 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700524
Daniel Normand5d70ea2019-06-05 15:13:43 -0700525 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700526 directory does not exist.
527
528 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700529 framework_target_files_dir: The name of a directory containing the special
530 items extracted from the framework target files package.
531 vendor_target_files_dir: The name of a directory containing the special
532 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700533 output_target_files_dir: The name of a directory that will be used to create
534 the output target files package after all the special cases are processed.
535 """
536
537 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700538 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700539 'dynamic_partitions_info.txt')):
540 return
541
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900542 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700543
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900544 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
545 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
546 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
547 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700548
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700549 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700550 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800551 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700552
553 output_dynamic_partitions_info_txt = os.path.join(
554 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700555 write_sorted_data(
556 data=merged_dynamic_partitions_dict,
557 path=output_dynamic_partitions_info_txt)
558
559
Bill Peckham19c3feb2020-03-20 18:31:43 -0700560def item_list_to_partition_set(item_list):
561 """Converts a target files item list to a partition set.
562
563 The item list contains items that might look like 'SYSTEM/*' or 'VENDOR/*' or
564 'OTA/android-info.txt'. Items that end in '/*' are assumed to match entire
565 directories where 'SYSTEM' or 'VENDOR' is a directory name that identifies the
566 contents of a partition of the same name. Other items in the list, such as the
567 'OTA' example contain metadata. This function iterates such a list, returning
568 a set that contains the partition entries.
569
570 Args:
571 item_list: A list of items in a target files package.
Daniel Normanb0c75912020-09-24 14:30:21 -0700572
Bill Peckham19c3feb2020-03-20 18:31:43 -0700573 Returns:
574 A set of partitions extracted from the list of items.
575 """
576
577 partition_set = set()
578
579 for item in item_list:
580 match = PARTITION_ITEM_PATTERN.search(item.strip())
581 partition_tag = match.group(1).lower() if match else None
582
583 if partition_tag:
584 partition_set.add(partition_tag)
585
586 return partition_set
587
588
Daniel Normand5d70ea2019-06-05 15:13:43 -0700589def process_apex_keys_apk_certs_common(framework_target_files_dir,
590 vendor_target_files_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700591 output_target_files_dir,
592 framework_partition_set,
593 vendor_partition_set, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700594 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700595
596 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700597 META/apkcerts.txt files from the framework directory and the vendor directory,
598 placing the merged result in the output directory. The precondition in that
599 the files are already extracted. The post condition is that the output
600 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700601
602 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700603 framework_target_files_dir: The name of a directory containing the special
604 items extracted from the framework target files package.
605 vendor_target_files_dir: The name of a directory containing the special
606 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700607 output_target_files_dir: The name of a directory that will be used to create
608 the output target files package after all the special cases are processed.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700609 framework_partition_set: Partitions that are considered framework
610 partitions. Used to filter apexkeys.txt and apkcerts.txt.
611 vendor_partition_set: Partitions that are considered vendor partitions. Used
612 to filter apexkeys.txt and apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700613 file_name: The name of the file to merge. One of apkcerts.txt or
614 apexkeys.txt.
615 """
616
617 def read_helper(d):
618 temp = {}
619 file_path = os.path.join(d, 'META', file_name)
620 with open(file_path) as f:
621 for line in f:
622 if line.strip():
Bill Peckham19c3feb2020-03-20 18:31:43 -0700623 name = line.split()[0]
624 match = MODULE_KEY_PATTERN.search(name)
625 temp[match.group(1)] = line.strip()
Chris Grossfabf50a2019-05-02 12:42:09 -0700626 return temp
627
Daniel Normand5d70ea2019-06-05 15:13:43 -0700628 framework_dict = read_helper(framework_target_files_dir)
629 vendor_dict = read_helper(vendor_target_files_dir)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700630 merged_dict = {}
Chris Grossfabf50a2019-05-02 12:42:09 -0700631
Bill Peckham19c3feb2020-03-20 18:31:43 -0700632 def filter_into_merged_dict(item_dict, partition_set):
633 for key, value in item_dict.items():
634 match = PARTITION_TAG_PATTERN.search(value)
635
636 if match is None:
637 raise ValueError('Entry missing partition tag: %s' % value)
638
639 partition_tag = match.group(1)
640
641 if partition_tag in partition_set:
642 if key in merged_dict:
Daniel Normanb0c75912020-09-24 14:30:21 -0700643 if OPTIONS.allow_duplicate_apkapex_keys:
644 # TODO(b/150582573) Always raise on duplicates.
645 logger.warning('Duplicate key %s' % key)
646 continue
647 else:
648 raise ValueError('Duplicate key %s' % key)
Bill Peckham19c3feb2020-03-20 18:31:43 -0700649
650 merged_dict[key] = value
651
652 filter_into_merged_dict(framework_dict, framework_partition_set)
653 filter_into_merged_dict(vendor_dict, vendor_partition_set)
Chris Grossfabf50a2019-05-02 12:42:09 -0700654
655 output_file = os.path.join(output_target_files_dir, 'META', file_name)
656
Bill Peckham19c3feb2020-03-20 18:31:43 -0700657 # The following code is similar to write_sorted_data, but different enough
658 # that we couldn't use that function. We need the output to be sorted by the
659 # basename of the apex/apk (without the ".apex" or ".apk" suffix). This
660 # allows the sort to be consistent with the framework/vendor input data and
661 # eases comparison of input data with merged data.
662 with open(output_file, 'w') as output:
663 for key in sorted(merged_dict.keys()):
664 out_str = merged_dict[key] + '\n'
665 output.write(out_str)
Daniel Normana61cde02019-05-03 14:19:13 -0700666
667
Daniel Normand5d70ea2019-06-05 15:13:43 -0700668def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700669 output_target_files_dir):
670 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700671 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
672 'framework_file_contexts.bin')
673 if not os.path.exists(framework_fc_path):
674 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
675 'file_contexts.bin')
676 if not os.path.exists(framework_fc_path):
677 raise ValueError('Missing framework file_contexts.bin.')
678 shutil.copyfile(
679 framework_fc_path,
680 os.path.join(output_target_files_dir, 'META',
681 'framework_file_contexts.bin'))
682
683 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
684 'vendor_file_contexts.bin')
685 if not os.path.exists(vendor_fc_path):
686 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700687 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700688 if not os.path.exists(vendor_fc_path):
689 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700690 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700691 vendor_fc_path,
692 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700693
694
Daniel Norman571e1822021-06-25 17:18:25 -0700695def compile_split_sepolicy(product_out, partition_map):
Daniel Norman48603ff2021-02-22 15:15:24 -0800696 """Uses secilc to compile a split sepolicy file.
697
698 Depends on various */etc/selinux/* and */etc/vintf/* files within partitions.
699
700 Args:
701 product_out: PRODUCT_OUT directory, containing partition directories.
702 partition_map: A map of partition name -> relative path within product_out.
Daniel Norman48603ff2021-02-22 15:15:24 -0800703
704 Returns:
705 A command list that can be executed to create the compiled sepolicy.
706 """
707
708 def get_file(partition, path):
709 if partition not in partition_map:
710 logger.warning('Cannot load SEPolicy files for missing partition %s',
711 partition)
712 return None
713 return os.path.join(product_out, partition_map[partition], path)
714
715 # Load the kernel sepolicy version from the FCM. This is normally provided
716 # directly to selinux.cpp as a build flag, but is also available in this file.
717 fcm_file = get_file('system', 'etc/vintf/compatibility_matrix.device.xml')
718 if not fcm_file or not os.path.exists(fcm_file):
719 raise ExternalError('Missing required file for loading sepolicy: %s', fcm)
720 kernel_sepolicy_version = ElementTree.parse(fcm_file).getroot().find(
721 'sepolicy/kernel-sepolicy-version').text
722
723 # Load the vendor's plat sepolicy version. This is the version used for
724 # locating sepolicy mapping files.
725 vendor_plat_version_file = get_file('vendor',
726 'etc/selinux/plat_sepolicy_vers.txt')
727 if not vendor_plat_version_file or not os.path.exists(
Daniel Norman2d7989a2021-04-05 17:40:47 +0000728 vendor_plat_version_file):
Daniel Norman48603ff2021-02-22 15:15:24 -0800729 raise ExternalError('Missing required sepolicy file %s',
730 vendor_plat_version_file)
731 with open(vendor_plat_version_file) as f:
732 vendor_plat_version = f.read().strip()
733
734 # Use the same flags and arguments as selinux.cpp OpenSplitPolicy().
735 cmd = ['secilc', '-m', '-M', 'true', '-G', '-N']
736 cmd.extend(['-c', kernel_sepolicy_version])
Daniel Norman571e1822021-06-25 17:18:25 -0700737 cmd.extend(['-o', os.path.join(product_out, 'META/combined_sepolicy')])
Daniel Norman48603ff2021-02-22 15:15:24 -0800738 cmd.extend(['-f', '/dev/null'])
739
740 required_policy_files = (
741 ('system', 'etc/selinux/plat_sepolicy.cil'),
742 ('system', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
743 ('vendor', 'etc/selinux/vendor_sepolicy.cil'),
744 ('vendor', 'etc/selinux/plat_pub_versioned.cil'),
745 )
746 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
747 required_policy_files)):
748 if not policy or not os.path.exists(policy):
749 raise ExternalError('Missing required sepolicy file %s', policy)
750 cmd.append(policy)
751
752 optional_policy_files = (
753 ('system', 'etc/selinux/mapping/%s.compat.cil' % vendor_plat_version),
754 ('system_ext', 'etc/selinux/system_ext_sepolicy.cil'),
755 ('system_ext', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
756 ('product', 'etc/selinux/product_sepolicy.cil'),
757 ('product', 'etc/selinux/mapping/%s.cil' % vendor_plat_version),
758 ('odm', 'etc/selinux/odm_sepolicy.cil'),
759 )
760 for policy in (map(lambda partition_and_path: get_file(*partition_and_path),
761 optional_policy_files)):
762 if policy and os.path.exists(policy):
763 cmd.append(policy)
764
765 return cmd
766
767
Daniel Normane9af70a2021-04-15 16:39:22 -0700768def validate_merged_apex_info(output_target_files_dir, partitions):
769 """Validates the APEX files in the merged target files directory.
770
771 Checks the APEX files in all possible preinstalled APEX directories.
772 Depends on the <partition>/apex/* APEX files within partitions.
773
774 Args:
Daniel Norman571e1822021-06-25 17:18:25 -0700775 output_target_files_dir: Output directory containing merged partition
776 directories.
Daniel Normane9af70a2021-04-15 16:39:22 -0700777 partitions: A list of all the partitions in the output directory.
778
779 Raises:
780 RuntimeError: if apex_utils fails to parse any APEX file.
781 ExternalError: if the same APEX package is provided by multiple partitions.
782 """
783 apex_packages = set()
784
785 apex_partitions = ('system', 'system_ext', 'product', 'vendor')
786 for partition in filter(lambda p: p in apex_partitions, partitions):
787 apex_info = apex_utils.GetApexInfoFromTargetFiles(
788 output_target_files_dir, partition, compressed_only=False)
789 partition_apex_packages = set([info.package_name for info in apex_info])
790 duplicates = apex_packages.intersection(partition_apex_packages)
791 if duplicates:
792 raise ExternalError(
793 'Duplicate APEX packages found in multiple partitions: %s' %
794 ' '.join(duplicates))
795 apex_packages.update(partition_apex_packages)
796
797
Daniel Normandb8cacc2021-04-09 15:34:43 -0700798def generate_care_map(partitions, output_target_files_dir):
799 """Generates a merged META/care_map.pb file in the output target files dir.
800
801 Depends on the info dict from META/misc_info.txt, as well as built images
802 within IMAGES/.
803
804 Args:
805 partitions: A list of partitions to potentially include in the care map.
806 output_target_files_dir: The name of a directory that will be used to create
807 the output target files package after all the special cases are processed.
808 """
809 OPTIONS.info_dict = common.LoadInfoDict(output_target_files_dir)
810 partition_image_map = {}
811 for partition in partitions:
812 image_path = os.path.join(output_target_files_dir, 'IMAGES',
813 '{}.img'.format(partition))
814 if os.path.exists(image_path):
815 partition_image_map[partition] = image_path
816 # Regenerated images should have their image_size property already set.
817 image_size_prop = '{}_image_size'.format(partition)
818 if image_size_prop not in OPTIONS.info_dict:
819 # Images copied directly from input target files packages will need
820 # their image sizes calculated.
821 partition_size = sparse_img.GetImagePartitionSize(image_path)
822 image_props = build_image.ImagePropFromGlobalDict(
823 OPTIONS.info_dict, partition)
824 verity_image_builder = verity_utils.CreateVerityImageBuilder(
825 image_props)
826 image_size = verity_image_builder.CalculateMaxImageSize(partition_size)
827 OPTIONS.info_dict[image_size_prop] = image_size
828
829 AddCareMapForAbOta(
830 os.path.join(output_target_files_dir, 'META', 'care_map.pb'),
831 PARTITIONS_WITH_CARE_MAP, partition_image_map)
832
833
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700834def process_special_cases(temp_dir, framework_meta, vendor_meta,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700835 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700836 framework_misc_info_keys, framework_partition_set,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700837 vendor_partition_set, framework_dexpreopt_tools,
838 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -0700839 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800840
841 Certain files in the output target files package require special-case
842 processing. This function performs all that special-case processing.
843
844 Args:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700845 temp_dir: Location containing an 'output' directory where target files have
846 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
847 framework_meta: The name of a directory containing the special items
848 extracted from the framework target files package.
849 vendor_meta: The name of a directory containing the special items
850 extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700851 output_target_files_temp_dir: The name of a directory that will be used to
852 create the output target files package after all the special cases are
853 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700854 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700855 instance of META/misc_info.txt. The remaining keys should come from the
856 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700857 framework_partition_set: Partitions that are considered framework
858 partitions. Used to filter apexkeys.txt and apkcerts.txt.
859 vendor_partition_set: Partitions that are considered vendor partitions. Used
860 to filter apexkeys.txt and apkcerts.txt.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700861
862 The following are only used if dexpreopt is applied:
863
864 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
865 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
866 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800867 """
868
Daniel Normand5d70ea2019-06-05 15:13:43 -0700869 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700870 process_ab_partitions_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700871 framework_target_files_temp_dir=framework_meta,
872 vendor_target_files_temp_dir=vendor_meta,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700873 output_target_files_temp_dir=output_target_files_temp_dir)
874
Daniel Norman72c626f2019-05-13 15:58:14 -0700875 copy_file_contexts(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700876 framework_target_files_dir=framework_meta,
877 vendor_target_files_dir=vendor_meta,
Daniel Norman72c626f2019-05-13 15:58:14 -0700878 output_target_files_dir=output_target_files_temp_dir)
879
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800880 process_misc_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700881 framework_target_files_temp_dir=framework_meta,
882 vendor_target_files_temp_dir=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800883 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700884 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800885
Daniel Normana61cde02019-05-03 14:19:13 -0700886 process_dynamic_partitions_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700887 framework_target_files_dir=framework_meta,
888 vendor_target_files_dir=vendor_meta,
Daniel Norman714bd122019-05-08 16:20:02 -0700889 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700890
Chris Grossfabf50a2019-05-02 12:42:09 -0700891 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700892 framework_target_files_dir=framework_meta,
893 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700894 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700895 framework_partition_set=framework_partition_set,
896 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700897 file_name='apkcerts.txt')
898
899 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700900 framework_target_files_dir=framework_meta,
901 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700902 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700903 framework_partition_set=framework_partition_set,
904 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700905 file_name='apexkeys.txt')
906
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700907 process_dexopt(
908 temp_dir=temp_dir,
909 framework_meta=framework_meta,
910 vendor_meta=vendor_meta,
911 output_target_files_temp_dir=output_target_files_temp_dir,
912 framework_dexpreopt_tools=framework_dexpreopt_tools,
913 framework_dexpreopt_config=framework_dexpreopt_config,
914 vendor_dexpreopt_config=vendor_dexpreopt_config)
915
916
917def process_dexopt(temp_dir, framework_meta, vendor_meta,
918 output_target_files_temp_dir,
919 framework_dexpreopt_tools, framework_dexpreopt_config,
920 vendor_dexpreopt_config):
921 """If needed, generates dexopt files for vendor apps.
922
923 Args:
924 temp_dir: Location containing an 'output' directory where target files have
925 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES, etc.
926 framework_meta: The name of a directory containing the special items
927 extracted from the framework target files package.
928 vendor_meta: The name of a directory containing the special items extracted
929 from the vendor target files package.
930 output_target_files_temp_dir: The name of a directory that will be used to
931 create the output target files package after all the special cases are
932 processed.
933 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
934 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
935 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
936 """
937 # Load vendor and framework META/misc_info.txt.
938 misc_info_path = ['META', 'misc_info.txt']
939 vendor_misc_info_dict = common.LoadDictionaryFromFile(
940 os.path.join(vendor_meta, *misc_info_path))
941
942 if (vendor_misc_info_dict.get('building_with_vsdk') != 'true' or
943 framework_dexpreopt_tools is None or
944 framework_dexpreopt_config is None or
945 vendor_dexpreopt_config is None):
946 return
947
948 logger.info('applying dexpreopt')
949
950 # The directory structure to apply dexpreopt is:
951 #
952 # <temp_dir>/
953 # framework_meta/
954 # META/
955 # vendor_meta/
956 # META/
957 # output/
958 # SYSTEM/
959 # VENDOR/
960 # IMAGES/
961 # <other items extracted from system and vendor target files>
962 # tools/
963 # <contents of dexpreopt_tools.zip>
964 # system_config/
965 # <contents of system dexpreopt_config.zip>
966 # vendor_config/
967 # <contents of vendor dexpreopt_config.zip>
968 # system -> output/SYSTEM
969 # vendor -> output/VENDOR
970 # apex -> output/SYSTEM/apex (only for flattened APEX builds)
971 # apex/ (extracted updatable APEX)
972 # <apex 1>/
973 # ...
974 # <apex 2>/
975 # ...
976 # ...
977 # out/dex2oat_result/vendor/
978 # <app>
979 # oat/arm64/
980 # package.vdex
981 # package.odex
982 # <priv-app>
983 # oat/arm64/
984 # package.vdex
985 # package.odex
986 dexpreopt_tools_files_temp_dir = os.path.join(temp_dir, 'tools')
987 dexpreopt_framework_config_files_temp_dir = os.path.join(temp_dir, 'system_config')
988 dexpreopt_vendor_config_files_temp_dir = os.path.join(temp_dir, 'vendor_config')
989
990 extract_items(
991 target_files=OPTIONS.framework_dexpreopt_tools,
992 target_files_temp_dir=dexpreopt_tools_files_temp_dir,
993 extract_item_list=('*',))
994 extract_items(
995 target_files=OPTIONS.framework_dexpreopt_config,
996 target_files_temp_dir=dexpreopt_framework_config_files_temp_dir,
997 extract_item_list=('*',))
998 extract_items(
999 target_files=OPTIONS.vendor_dexpreopt_config,
1000 target_files_temp_dir=dexpreopt_vendor_config_files_temp_dir,
1001 extract_item_list=('*',))
1002
1003 os.symlink(os.path.join(output_target_files_temp_dir, "SYSTEM"),
1004 os.path.join(temp_dir, "system"))
1005 os.symlink(os.path.join(output_target_files_temp_dir, "VENDOR"),
1006 os.path.join(temp_dir, "vendor"))
1007
1008 # The directory structure for flatteded APEXes is:
1009 #
1010 # SYSTEM
1011 # apex
1012 # <APEX name, e.g., com.android.wifi>
1013 # apex_manifest.pb
1014 # apex_pubkey
1015 # etc/
1016 # javalib/
1017 # lib/
1018 # lib64/
1019 # priv-app/
1020 #
1021 # The directory structure for updatable APEXes is:
1022 #
1023 # SYSTEM
1024 # apex
1025 # com.android.adbd.apex
1026 # com.android.appsearch.apex
1027 # com.android.art.apex
1028 # ...
1029 apex_root = os.path.join(output_target_files_temp_dir, "SYSTEM", "apex")
1030 framework_misc_info_dict = common.LoadDictionaryFromFile(
1031 os.path.join(framework_meta, *misc_info_path))
1032
1033 # Check for flattended versus updatable APEX.
1034 if framework_misc_info_dict.get('target_flatten_apex') == 'false':
1035 # Extract APEX.
1036 logging.info('extracting APEX')
1037
1038 apex_extract_root_dir = os.path.join(temp_dir, 'apex')
1039 os.makedirs(apex_extract_root_dir)
1040
1041 for apex in (glob.glob(os.path.join(apex_root, '*.apex')) +
1042 glob.glob(os.path.join(apex_root, '*.capex'))):
1043 logging.info(' apex: %s', apex)
1044 # deapexer is in the same directory as the merge_target_files binary extracted
1045 # from otatools.zip.
1046 apex_json_info = subprocess.check_output(['deapexer', 'info', apex])
1047 logging.info(' info: %s', apex_json_info)
1048 apex_info = json.loads(apex_json_info)
1049 apex_name = apex_info['name']
1050 logging.info(' name: %s', apex_name)
1051
1052 apex_extract_dir = os.path.join(apex_extract_root_dir, apex_name)
1053 os.makedirs(apex_extract_dir)
1054
1055 # deapexer uses debugfs_static, which is part of otatools.zip.
1056 command = [
1057 'deapexer',
1058 '--debugfs_path',
1059 'debugfs_static',
1060 'extract',
1061 apex,
1062 apex_extract_dir,
1063 ]
1064 logging.info(' running %s', command)
1065 subprocess.check_call(command)
1066 else:
1067 # Flattened APEXes don't need to be extracted since they have the necessary
1068 # directory structure.
1069 os.symlink(os.path.join(apex_root), os.path.join(temp_dir, 'apex'))
1070
1071 # Modify system config to point to the tools that have been extracted.
1072 # Absolute or .. paths are not allowed by the dexpreopt_gen tool in
1073 # dexpreopt_soong.config.
1074 dexpreopt_framework_soon_config = os.path.join(
1075 dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config')
1076 with open(dexpreopt_framework_soon_config, 'w') as f:
1077 dexpreopt_soong_config = {
1078 'Profman': 'tools/profman',
1079 'Dex2oat': 'tools/dex2oatd',
1080 'Aapt': 'tools/aapt2',
1081 'SoongZip': 'tools/soong_zip',
1082 'Zip2zip': 'tools/zip2zip',
1083 'ManifestCheck': 'tools/manifest_check',
1084 'ConstructContext': 'tools/construct_context',
1085 }
1086 json.dump(dexpreopt_soong_config, f)
1087
1088 # TODO(b/188179859): Make *dex location configurable to vendor or system_other.
1089 use_system_other_odex = False
1090
1091 if use_system_other_odex:
1092 dex_img = 'SYSTEM_OTHER'
1093 else:
1094 dex_img = 'VENDOR'
1095 # Open vendor_filesystem_config to append the items generated by dexopt.
1096 vendor_file_system_config = open(
1097 os.path.join(temp_dir, 'output', 'META', 'vendor_filesystem_config.txt'),
1098 'a')
1099
1100 # Dexpreopt vendor apps.
1101 dexpreopt_config_suffix = '_dexpreopt.config'
1102 for config in glob.glob(os.path.join(
1103 dexpreopt_vendor_config_files_temp_dir, '*' + dexpreopt_config_suffix)):
1104 app = os.path.basename(config)[:-len(dexpreopt_config_suffix)]
1105 logging.info('dexpreopt config: %s %s', config, app)
1106
1107 apk_dir = 'app'
1108 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1109 if not os.path.exists(apk_path):
1110 apk_dir = 'priv-app'
1111 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1112 if not os.path.exists(apk_path):
1113 logging.warning('skipping dexpreopt for %s, no apk found in vendor/app '
1114 'or vendor/priv-app', app)
1115 continue
1116
1117 # Generate dexpreopting script. Note 'out_dir' is not the output directory
1118 # where the script is generated, but the OUT_DIR at build time referenced
1119 # in the dexpreot config files, e.g., "out/.../core-oj.jar", so the tool knows
1120 # how to adjust the path.
1121 command = [
1122 os.path.join(dexpreopt_tools_files_temp_dir, 'dexpreopt_gen'),
1123 '-global',
1124 os.path.join(dexpreopt_framework_config_files_temp_dir, 'dexpreopt.config'),
1125 '-global_soong',
1126 os.path.join(
1127 dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config'),
1128 '-module',
1129 config,
1130 '-dexpreopt_script',
1131 'dexpreopt_app.sh',
1132 '-out_dir',
1133 'out',
1134 '-base_path',
1135 '.',
1136 '--uses_target_files',
1137 ]
1138
1139 # Run the command from temp_dir so all tool paths are its descendants.
1140 logging.info("running %s", command)
1141 subprocess.check_call(command, cwd = temp_dir)
1142
1143 # Call the generated script.
1144 command = ['sh', 'dexpreopt_app.sh', apk_path]
1145 logging.info("running %s", command)
1146 subprocess.check_call(command, cwd = temp_dir)
1147
1148 # Output files are in:
1149 #
1150 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.vdex
1151 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.odex
1152 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.vdex
1153 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.odex
1154 #
1155 # Copy the files to their destination. The structure of system_other is:
1156 #
1157 # system_other/
1158 # system-other-odex-marker
1159 # system/
1160 # app/
1161 # <app>/oat/arm64/
1162 # <app>.odex
1163 # <app>.vdex
1164 # ...
1165 # priv-app/
1166 # <app>/oat/arm64/
1167 # <app>.odex
1168 # <app>.vdex
1169 # ...
1170
1171 # TODO(b/188179859): Support for other architectures.
1172 arch = 'arm64'
1173
1174 dex_destination = os.path.join(temp_dir, 'output', dex_img, apk_dir, app, 'oat', arch)
1175 os.makedirs(dex_destination)
1176 dex2oat_path = os.path.join(
1177 temp_dir, 'out', 'dex2oat_result', 'vendor', apk_dir, app, 'oat', arch)
1178 shutil.copy(os.path.join(dex2oat_path, 'package.vdex'),
1179 os.path.join(dex_destination, app + '.vdex'))
1180 shutil.copy(os.path.join(dex2oat_path, 'package.odex'),
1181 os.path.join(dex_destination, app + '.odex'))
1182
1183 # Append entries to vendor_file_system_config.txt, such as:
1184 #
1185 # vendor/app/<app>/oat 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1186 # vendor/app/<app>/oat/arm64 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1187 # vendor/app/<app>/oat/arm64/<app>.odex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1188 # vendor/app/<app>/oat/arm64/<app>.vdex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1189 if not use_system_other_odex:
1190 vendor_app_prefix = 'vendor/' + apk_dir + '/' + app + '/oat'
1191 selabel = 'selabel=u:object_r:vendor_app_file:s0 capabilities=0x0'
1192 vendor_file_system_config.writelines([
1193 vendor_app_prefix + ' 0 2000 755 ' + selabel + '\n',
1194 vendor_app_prefix + '/' + arch + ' 0 2000 755 ' + selabel + '\n',
1195 vendor_app_prefix + '/' + arch + '/' + app + '.odex 0 0 644 ' + selabel + '\n',
1196 vendor_app_prefix + '/' + arch + '/' + app + '.vdex 0 0 644 ' + selabel + '\n',
1197 ])
1198
1199 if not use_system_other_odex:
1200 vendor_file_system_config.close()
1201 # Delete vendor.img so that it will be regenerated.
1202 # TODO(b/188179859): Rebuilding a vendor image in GRF mode (e.g., T(framework)
1203 # and S(vendor) may require logic similar to that in
1204 # rebuild_image_with_sepolicy.
1205 vendor_img = os.path.join(output_target_files_temp_dir, 'IMAGES', 'vendor.img')
1206 if os.path.exists(vendor_img):
1207 logging.info('Deleting %s', vendor_img)
1208 os.remove(vendor_img)
1209
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001210
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001211def create_merged_package(temp_dir, framework_target_files, framework_item_list,
1212 vendor_target_files, vendor_item_list,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001213 framework_misc_info_keys, rebuild_recovery,
1214 framework_dexpreopt_tools, framework_dexpreopt_config,
1215 vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001216 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001217
1218 Args:
1219 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -07001220 input target files packages, and also a scratch directory that we use for
1221 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001222 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001223 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001224 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001225 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -07001226 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001227 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001228 vendor_target_files: The name of the zip archive containing the vendor
1229 partial target files package.
1230 vendor_item_list: The list of items to extract from the partial vendor
1231 target files package as is, meaning these items will land in the output
1232 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -07001233 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001234 framework_misc_info_keys: A list of keys to obtain from the framework
1235 instance of META/misc_info.txt. The remaining keys should come from the
1236 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -07001237 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -07001238 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001239
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001240 The following are only used if dexpreopt is applied:
1241
1242 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1243 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1244 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
1245
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001246 Returns:
1247 Path to merged package under temp directory.
1248 """
Daniel Normandbbf5a32020-10-22 16:03:32 -07001249 # Extract "as is" items from the input framework and vendor partial target
1250 # files packages directly into the output temporary directory, since these items
1251 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001252
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001253 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -08001254 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001255 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001256 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001257 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -08001258 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001259 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001260 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001261 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001262
Daniel Normandbbf5a32020-10-22 16:03:32 -07001263 # Perform special case processing on META/* items.
1264 # After this function completes successfully, all the files we need to create
1265 # the output target files package are in place.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001266 framework_meta = os.path.join(temp_dir, 'framework_meta')
1267 vendor_meta = os.path.join(temp_dir, 'vendor_meta')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001268 extract_items(
1269 target_files=framework_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001270 target_files_temp_dir=framework_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001271 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001272 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001273 target_files=vendor_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001274 target_files_temp_dir=vendor_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001275 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001276 process_special_cases(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001277 temp_dir=temp_dir,
1278 framework_meta=framework_meta,
1279 vendor_meta=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001280 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -07001281 framework_misc_info_keys=framework_misc_info_keys,
1282 framework_partition_set=item_list_to_partition_set(framework_item_list),
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001283 vendor_partition_set=item_list_to_partition_set(vendor_item_list),
1284 framework_dexpreopt_tools=framework_dexpreopt_tools,
1285 framework_dexpreopt_config=framework_dexpreopt_config,
1286 vendor_dexpreopt_config=vendor_dexpreopt_config)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001287
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001288 return output_target_files_temp_dir
1289
1290
1291def generate_images(target_files_dir, rebuild_recovery):
1292 """Generate images from target files.
1293
1294 This function takes merged output temporary directory and create images
1295 from it.
1296
1297 Args:
1298 target_files_dir: Path to merged temp directory.
1299 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1300 devices and write it to the system image.
1301 """
1302
1303 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001304
Daniel Normandbbf5a32020-10-22 16:03:32 -07001305 add_img_args = [
1306 '--verbose',
1307 '--add_missing',
1308 ]
Bill Peckhame868aec2019-09-17 17:06:47 -07001309 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -07001310 if rebuild_recovery:
1311 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001312 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001313
1314 add_img_to_target_files.main(add_img_args)
1315
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001316
Daniel Norman571e1822021-06-25 17:18:25 -07001317def rebuild_image_with_sepolicy(target_files_dir,
1318 vendor_otatools=None,
1319 vendor_target_files=None):
1320 """Rebuilds odm.img or vendor.img to include merged sepolicy files.
1321
1322 If odm is present then odm is preferred -- otherwise vendor is used.
1323
1324 Args:
1325 target_files_dir: Path to the extracted merged target-files package.
1326 vendor_otatools: If not None, path to an otatools.zip from the vendor build
1327 that is used when recompiling the image.
1328 vendor_target_files: Expected if vendor_otatools is not None. Path to the
1329 vendor target-files zip.
1330 """
1331 partition = 'vendor'
1332 if os.path.exists(os.path.join(target_files_dir, 'ODM')) or os.path.exists(
1333 os.path.join(target_files_dir, 'IMAGES/odm.img')):
1334 partition = 'odm'
1335 partition_img = '{}.img'.format(partition)
1336
1337 logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
1338
1339 # Copy the combined SEPolicy file and framework hashes to the image that is
1340 # being rebuilt.
1341 def copy_selinux_file(input_path, output_filename):
Po Hu0e4403e2021-07-06 17:05:56 +08001342 input_filename = os.path.join(target_files_dir, input_path)
1343 if not os.path.exists(input_filename):
1344 input_filename = input_filename.replace('SYSTEM_EXT/', 'SYSTEM/system_ext/') \
1345 .replace('PRODUCT/', 'SYSTEM/product/')
1346 if not os.path.exists(input_filename):
1347 logger.info('Skipping copy_selinux_file for %s', input_filename)
1348 return
Daniel Norman571e1822021-06-25 17:18:25 -07001349 shutil.copy(
Po Hu0e4403e2021-07-06 17:05:56 +08001350 input_filename,
Daniel Norman571e1822021-06-25 17:18:25 -07001351 os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
1352 output_filename))
1353
1354 copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy')
1355 copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256',
1356 'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256')
1357 copy_selinux_file(
1358 'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256',
1359 'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256')
1360 copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256',
1361 'precompiled_sepolicy.product_sepolicy_and_mapping.sha256')
1362
1363 if not vendor_otatools:
1364 # Remove the partition from the merged target-files archive. It will be
1365 # rebuilt later automatically by generate_images().
1366 os.remove(os.path.join(target_files_dir, 'IMAGES', partition_img))
1367 else:
1368 # TODO(b/192253131): Remove the need for vendor_otatools by fixing
1369 # backwards-compatibility issues when compiling images on R from S+.
1370 if not vendor_target_files:
1371 raise ValueError(
1372 'Expected vendor_target_files if vendor_otatools is not None.')
1373 logger.info(
1374 '%s recompilation will be performed using the vendor otatools.zip',
1375 partition_img)
1376
1377 # Unzip the vendor build's otatools.zip and target-files archive.
1378 vendor_otatools_dir = common.MakeTempDir(
1379 prefix='merge_target_files_vendor_otatools_')
1380 vendor_target_files_dir = common.MakeTempDir(
1381 prefix='merge_target_files_vendor_target_files_')
1382 common.UnzipToDir(vendor_otatools, vendor_otatools_dir)
1383 common.UnzipToDir(vendor_target_files, vendor_target_files_dir)
1384
1385 # Copy the partition contents from the merged target-files archive to the
1386 # vendor target-files archive.
1387 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
1388 shutil.copytree(
1389 os.path.join(target_files_dir, partition.upper()),
Po Hu0e4403e2021-07-06 17:05:56 +08001390 os.path.join(vendor_target_files_dir, partition.upper()),
1391 symlinks=True)
Daniel Norman571e1822021-06-25 17:18:25 -07001392
1393 # Delete then rebuild the partition.
1394 os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
1395 rebuild_partition_command = [
1396 os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
1397 '--verbose',
1398 '--add_missing',
1399 vendor_target_files_dir,
1400 ]
1401 logger.info('Recompiling %s: %s', partition_img,
1402 ' '.join(rebuild_partition_command))
1403 common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
1404
1405 # Move the newly-created image to the merged target files dir.
Po Hu0e4403e2021-07-06 17:05:56 +08001406 if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')):
1407 os.makedirs(os.path.join(target_files_dir, 'IMAGES'))
Daniel Norman571e1822021-06-25 17:18:25 -07001408 shutil.move(
1409 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
1410 os.path.join(target_files_dir, 'IMAGES', partition_img))
1411
1412
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001413def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -07001414 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001415
1416 Args:
1417 target_dir: Path to the target file package which contains misc_info.txt for
1418 detailed information for super image.
1419 output_super_empty: If provided, copies a super_empty.img file from the
1420 target files package to this path.
1421 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001422 # Create super_empty.img using the merged misc_info.txt.
1423
Daniel Norman4cc9df62019-07-18 10:11:07 -07001424 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001425
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +09001426 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
1427 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001428
1429 if use_dynamic_partitions != 'true' and output_super_empty:
1430 raise ValueError(
1431 'Building super_empty.img requires use_dynamic_partitions=true.')
1432 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001433 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001434 build_super_image_args = [
1435 misc_info_txt,
1436 super_empty_img,
1437 ]
1438 build_super_image.main(build_super_image_args)
1439
1440 # Copy super_empty.img to the user-provided output_super_empty location.
1441 if output_super_empty:
1442 shutil.copyfile(super_empty_img, output_super_empty)
1443
Daniel Normanb8a2f9d2019-04-24 12:55:51 -07001444
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001445def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -07001446 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001447
1448 Args:
1449 output_file: The name of the zip archive target files package.
1450 source_dir: The target directory contains package to be archived.
1451 temp_dir: Path to temporary directory for any intermediate files.
1452 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001453 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001454 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001455 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001456
Daniel Normandbbf5a32020-10-22 16:03:32 -07001457 def files_from_path(target_path, extra_args=None):
1458 """Gets files under the given path and return a sorted list."""
1459 find_command = ['find', target_path] + (extra_args or [])
1460 find_process = common.Run(
1461 find_command, stdout=subprocess.PIPE, verbose=False)
1462 return common.RunAndCheckOutput(['sort'],
1463 stdin=find_process.stdout,
1464 verbose=False)
1465
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001466 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001467 other_content = files_from_path(
1468 source_dir,
1469 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001470
Tao Bao2ad4b822019-06-27 16:52:12 -07001471 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001472 f.write(meta_content)
1473 f.write(other_content)
1474
1475 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001476 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001477 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001478 '-o',
1479 output_zip,
1480 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001481 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001482 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001483 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001484 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001485
1486 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001487 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001488 logger.info('finished creating %s', output_file)
1489
1490 return output_zip
1491
1492
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001493def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1494 framework_misc_info_keys, vendor_target_files,
1495 vendor_item_list, output_target_files, output_dir,
1496 output_item_list, output_ota, output_img,
Daniel Norman571e1822021-06-25 17:18:25 -07001497 output_super_empty, rebuild_recovery, vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001498 rebuild_sepolicy, framework_dexpreopt_tools,
1499 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001500 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001501
1502 This function takes framework and vendor target files packages as input,
1503 performs various file extractions, special case processing, and finally
1504 creates a merged zip archive as output.
1505
1506 Args:
1507 temp_dir: The name of a directory we use when we extract items from the
1508 input target files packages, and also a scratch directory that we use for
1509 temporary files.
1510 framework_target_files: The name of the zip archive containing the framework
1511 partial target files package.
1512 framework_item_list: The list of items to extract from the partial framework
1513 target files package as is, meaning these items will land in the output
1514 target files package exactly as they appear in the input partial framework
1515 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001516 framework_misc_info_keys: A list of keys to obtain from the framework
1517 instance of META/misc_info.txt. The remaining keys should come from the
1518 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001519 vendor_target_files: The name of the zip archive containing the vendor
1520 partial target files package.
1521 vendor_item_list: The list of items to extract from the partial vendor
1522 target files package as is, meaning these items will land in the output
1523 target files package exactly as they appear in the input partial vendor
1524 target files package.
1525 output_target_files: The name of the output zip archive target files package
1526 created by merging framework and vendor.
1527 output_dir: The destination directory for saving merged files.
1528 output_item_list: The list of items to copy into the output_dir.
1529 output_ota: The name of the output zip archive ota package.
1530 output_img: The name of the output zip archive img package.
1531 output_super_empty: If provided, creates a super_empty.img file from the
1532 merged target files package and saves it at this path.
1533 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1534 devices and write it to the system image.
Daniel Norman571e1822021-06-25 17:18:25 -07001535 vendor_otatools: Path to an otatools zip used for recompiling vendor images.
1536 rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
1537 vendor.img using a merged precompiled_sepolicy file.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001538
1539 The following are only used if dexpreopt is applied:
1540
1541 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1542 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1543 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001544 """
1545
1546 logger.info('starting: merge framework %s and vendor %s into output %s',
1547 framework_target_files, vendor_target_files, output_target_files)
1548
1549 output_target_files_temp_dir = create_merged_package(
1550 temp_dir, framework_target_files, framework_item_list,
1551 vendor_target_files, vendor_item_list, framework_misc_info_keys,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001552 rebuild_recovery, framework_dexpreopt_tools, framework_dexpreopt_config,
1553 vendor_dexpreopt_config)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001554
Yifan Hongade0d3f2019-08-21 16:37:11 -07001555 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001556 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001557
Daniel Norman21c34f72020-11-11 17:25:50 -08001558 partition_map = common.PartitionMapFromTargetFiles(
1559 output_target_files_temp_dir)
1560
Daniel Normand3351562020-10-29 12:33:11 -07001561 # Generate and check for cross-partition violations of sharedUserId
1562 # values in APKs. This requires the input target-files packages to contain
1563 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001564 shareduid_violation_modules = os.path.join(
1565 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1566 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001567 violation = find_shareduid_violation.FindShareduidViolation(
1568 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001569
1570 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001571 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001572
1573 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001574 framework_partitions = item_list_to_partition_set(framework_item_list)
1575 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001576 shareduid_errors = common.SharedUidPartitionViolations(
1577 json.loads(violation), [framework_partitions, vendor_partitions])
1578 if shareduid_errors:
1579 for error in shareduid_errors:
1580 logger.error(error)
1581 raise ValueError('sharedUserId APK error. See %s' %
1582 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001583
Daniel Norman48603ff2021-02-22 15:15:24 -08001584 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001585 filtered_partitions = {
1586 partition: path
1587 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001588 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1589 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001590
1591 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001592 common.RunHostInitVerifier(
1593 product_out=output_target_files_temp_dir,
1594 partition_map=filtered_partitions)
1595
Daniel Norman48603ff2021-02-22 15:15:24 -08001596 # Check that the split sepolicy from the multiple builds can compile.
Daniel Norman571e1822021-06-25 17:18:25 -07001597 split_sepolicy_cmd = compile_split_sepolicy(output_target_files_temp_dir,
1598 filtered_partitions)
Daniel Norman48603ff2021-02-22 15:15:24 -08001599 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1600 common.RunAndCheckOutput(split_sepolicy_cmd)
Daniel Norman571e1822021-06-25 17:18:25 -07001601 # Include the compiled policy in an image if requested.
1602 if rebuild_sepolicy:
1603 rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
1604 vendor_target_files)
Daniel Norman48603ff2021-02-22 15:15:24 -08001605
Daniel Normane9af70a2021-04-15 16:39:22 -07001606 # Run validation checks on the pre-installed APEX files.
1607 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
1608
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001609 generate_images(output_target_files_temp_dir, rebuild_recovery)
1610
1611 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1612
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001613 # Finally, create the output target files zip archive and/or copy the
1614 # output items to the output target files directory.
1615
1616 if output_dir:
1617 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1618
1619 if not output_target_files:
1620 return
1621
Iavor-Valentin Iftimeb837b712022-01-27 16:29:37 +00001622 # Create the merged META/care_map.pb if A/B update
1623 if 'ab_update' in framework_misc_info_keys:
1624 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
Daniel Normandb8cacc2021-04-09 15:34:43 -07001625
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001626 output_zip = create_target_files_archive(output_target_files,
1627 output_target_files_temp_dir,
1628 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001629
Daniel Norman74eb74b2019-09-18 14:01:48 -07001630 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001631 if output_img:
1632 img_from_target_files.main([output_zip, output_img])
1633
Daniel Norman3b64ce12019-04-16 16:11:35 -07001634 # Create the OTA package from the merged target files package.
1635
1636 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001637 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001638
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001639
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001640def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001641 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001642
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001643 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001644 directory. It also cleans up the temporary directory.
1645
1646 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001647 func: The function to call. Should accept one parameter, the path to the
1648 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001649 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001650 """
1651
1652 # Create a temporary directory. This will serve as the parent of directories
1653 # we use when we extract items from the input target files packages, and also
1654 # a scratch directory that we use for temporary files.
1655
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001656 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1657
1658 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001659 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001660 finally:
1661 if keep_tmp:
1662 logger.info('keeping %s', temp_dir)
1663 else:
1664 common.Cleanup()
1665
1666
1667def main():
1668 """The main function.
1669
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001670 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001671 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001672 """
1673
1674 common.InitLogging()
1675
Bill Peckhamf753e152019-02-19 18:02:46 -08001676 def option_handler(o, a):
1677 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001678 logger.warning(
1679 '--system-target-files has been renamed to --framework-target-files')
1680 OPTIONS.framework_target_files = a
1681 elif o == '--framework-target-files':
1682 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001683 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001684 logger.warning(
1685 '--system-item-list has been renamed to --framework-item-list')
1686 OPTIONS.framework_item_list = a
1687 elif o == '--framework-item-list':
1688 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001689 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001690 logger.warning('--system-misc-info-keys has been renamed to '
1691 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001692 OPTIONS.framework_misc_info_keys = a
1693 elif o == '--framework-misc-info-keys':
1694 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001695 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001696 logger.warning(
1697 '--other-target-files has been renamed to --vendor-target-files')
1698 OPTIONS.vendor_target_files = a
1699 elif o == '--vendor-target-files':
1700 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001701 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001702 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001703 OPTIONS.vendor_item_list = a
1704 elif o == '--vendor-item-list':
1705 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001706 elif o == '--output-target-files':
1707 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001708 elif o == '--output-dir':
1709 OPTIONS.output_dir = a
1710 elif o == '--output-item-list':
1711 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001712 elif o == '--output-ota':
1713 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001714 elif o == '--output-img':
1715 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001716 elif o == '--output-super-empty':
1717 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001718 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001719 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001720 elif o == '--allow-duplicate-apkapex-keys':
1721 OPTIONS.allow_duplicate_apkapex_keys = True
Daniel Norman571e1822021-06-25 17:18:25 -07001722 elif o == '--vendor-otatools':
1723 OPTIONS.vendor_otatools = a
1724 elif o == '--rebuild-sepolicy':
1725 OPTIONS.rebuild_sepolicy = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001726 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001727 OPTIONS.keep_tmp = True
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001728 elif o == '--framework-dexpreopt-config':
1729 OPTIONS.framework_dexpreopt_config = a
1730 elif o == '--framework-dexpreopt-tools':
1731 OPTIONS.framework_dexpreopt_tools = a
1732 elif o == '--vendor-dexpreopt-config':
1733 OPTIONS.vendor_dexpreopt_config = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001734 else:
1735 return False
1736 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001737
Bill Peckhamf753e152019-02-19 18:02:46 -08001738 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001739 sys.argv[1:],
1740 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001741 extra_long_opts=[
1742 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001743 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001744 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001745 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001746 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001747 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001748 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001749 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001750 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001751 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001752 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001753 'output-dir=',
1754 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001755 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001756 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001757 'output-super-empty=',
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001758 'framework-dexpreopt-config=',
1759 'framework-dexpreopt-tools=',
1760 'vendor-dexpreopt-config=',
Daniel Normana4911da2019-03-15 14:36:21 -07001761 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001762 'allow-duplicate-apkapex-keys',
Daniel Norman571e1822021-06-25 17:18:25 -07001763 'vendor-otatools=',
1764 'rebuild-sepolicy',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001765 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001766 ],
1767 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001768
Tao Bao2ad4b822019-06-27 16:52:12 -07001769 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001770 if (args or OPTIONS.framework_target_files is None or
1771 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001772 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001773 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001774 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001775 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001776
Daniel Normand5d70ea2019-06-05 15:13:43 -07001777 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001778 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001779 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001780 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001781
Daniel Normand5d70ea2019-06-05 15:13:43 -07001782 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001783 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001784 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001785 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001786 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001787
Daniel Normand5d70ea2019-06-05 15:13:43 -07001788 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001789 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001790 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001791 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001792
Daniel Normanfdb38812019-04-15 09:47:24 -07001793 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001794 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001795 else:
1796 output_item_list = None
1797
Daniel Normane5964522019-03-19 10:32:03 -07001798 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001799 framework_item_list=framework_item_list,
1800 framework_misc_info_keys=framework_misc_info_keys,
1801 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001802 sys.exit(1)
1803
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001804 call_func_with_temp_dir(
1805 lambda temp_dir: merge_target_files(
1806 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001807 framework_target_files=OPTIONS.framework_target_files,
1808 framework_item_list=framework_item_list,
1809 framework_misc_info_keys=framework_misc_info_keys,
1810 vendor_target_files=OPTIONS.vendor_target_files,
1811 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001812 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001813 output_dir=OPTIONS.output_dir,
1814 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001815 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001816 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001817 output_super_empty=OPTIONS.output_super_empty,
Daniel Norman571e1822021-06-25 17:18:25 -07001818 rebuild_recovery=OPTIONS.rebuild_recovery,
1819 vendor_otatools=OPTIONS.vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001820 rebuild_sepolicy=OPTIONS.rebuild_sepolicy,
1821 framework_dexpreopt_tools=OPTIONS.framework_dexpreopt_tools,
1822 framework_dexpreopt_config=OPTIONS.framework_dexpreopt_config,
1823 vendor_dexpreopt_config=OPTIONS.vendor_dexpreopt_config), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001824
1825
1826if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001827 main()