blob: f72412df47418590ddb82bcc648d57ae8ce7a799 [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
Daniel Normana84d13b2022-02-17 14:16:40 -0800130from common import ExternalError
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
Daniel Normandb8cacc2021-04-09 15:34:43 -0700829
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700830def process_special_cases(temp_dir, framework_meta, vendor_meta,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700831 output_target_files_temp_dir,
Daniel Normanb0c75912020-09-24 14:30:21 -0700832 framework_misc_info_keys, framework_partition_set,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700833 vendor_partition_set, framework_dexpreopt_tools,
834 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -0700835 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800836
837 Certain files in the output target files package require special-case
838 processing. This function performs all that special-case processing.
839
840 Args:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700841 temp_dir: Location containing an 'output' directory where target files have
Daniel Normane292f5f2022-02-17 14:16:10 -0800842 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES,
843 etc.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700844 framework_meta: The name of a directory containing the special items
845 extracted from the framework target files package.
Daniel Normane292f5f2022-02-17 14:16:10 -0800846 vendor_meta: The name of a directory containing the special items extracted
847 from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700848 output_target_files_temp_dir: The name of a directory that will be used to
849 create the output target files package after all the special cases are
850 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700851 framework_misc_info_keys: A list of keys to obtain from the framework
Daniel Normandbbf5a32020-10-22 16:03:32 -0700852 instance of META/misc_info.txt. The remaining keys should come from the
853 vendor instance.
Bill Peckham19c3feb2020-03-20 18:31:43 -0700854 framework_partition_set: Partitions that are considered framework
855 partitions. Used to filter apexkeys.txt and apkcerts.txt.
856 vendor_partition_set: Partitions that are considered vendor partitions. Used
857 to filter apexkeys.txt and apkcerts.txt.
Daniel Normane292f5f2022-02-17 14:16:10 -0800858 Args used if dexpreopt is applied:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700859 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
860 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
861 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800862 """
863
Daniel Normand5d70ea2019-06-05 15:13:43 -0700864 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700865 process_ab_partitions_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700866 framework_target_files_temp_dir=framework_meta,
867 vendor_target_files_temp_dir=vendor_meta,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700868 output_target_files_temp_dir=output_target_files_temp_dir)
869
Daniel Norman72c626f2019-05-13 15:58:14 -0700870 copy_file_contexts(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700871 framework_target_files_dir=framework_meta,
872 vendor_target_files_dir=vendor_meta,
Daniel Norman72c626f2019-05-13 15:58:14 -0700873 output_target_files_dir=output_target_files_temp_dir)
874
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800875 process_misc_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700876 framework_target_files_temp_dir=framework_meta,
877 vendor_target_files_temp_dir=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800878 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700879 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800880
Daniel Normana61cde02019-05-03 14:19:13 -0700881 process_dynamic_partitions_info_txt(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700882 framework_target_files_dir=framework_meta,
883 vendor_target_files_dir=vendor_meta,
Daniel Norman714bd122019-05-08 16:20:02 -0700884 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700885
Chris Grossfabf50a2019-05-02 12:42:09 -0700886 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700887 framework_target_files_dir=framework_meta,
888 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700889 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700890 framework_partition_set=framework_partition_set,
891 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700892 file_name='apkcerts.txt')
893
894 process_apex_keys_apk_certs_common(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700895 framework_target_files_dir=framework_meta,
896 vendor_target_files_dir=vendor_meta,
Chris Grossfabf50a2019-05-02 12:42:09 -0700897 output_target_files_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -0700898 framework_partition_set=framework_partition_set,
899 vendor_partition_set=vendor_partition_set,
Chris Grossfabf50a2019-05-02 12:42:09 -0700900 file_name='apexkeys.txt')
901
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700902 process_dexopt(
903 temp_dir=temp_dir,
904 framework_meta=framework_meta,
905 vendor_meta=vendor_meta,
906 output_target_files_temp_dir=output_target_files_temp_dir,
907 framework_dexpreopt_tools=framework_dexpreopt_tools,
908 framework_dexpreopt_config=framework_dexpreopt_config,
909 vendor_dexpreopt_config=vendor_dexpreopt_config)
910
911
912def process_dexopt(temp_dir, framework_meta, vendor_meta,
Daniel Normane292f5f2022-02-17 14:16:10 -0800913 output_target_files_temp_dir, framework_dexpreopt_tools,
914 framework_dexpreopt_config, vendor_dexpreopt_config):
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700915 """If needed, generates dexopt files for vendor apps.
916
917 Args:
918 temp_dir: Location containing an 'output' directory where target files have
Daniel Normane292f5f2022-02-17 14:16:10 -0800919 been extracted, e.g. <temp_dir>/output/SYSTEM, <temp_dir>/output/IMAGES,
920 etc.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700921 framework_meta: The name of a directory containing the special items
922 extracted from the framework target files package.
923 vendor_meta: The name of a directory containing the special items extracted
924 from the vendor target files package.
925 output_target_files_temp_dir: The name of a directory that will be used to
926 create the output target files package after all the special cases are
927 processed.
928 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
929 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
930 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
931 """
932 # Load vendor and framework META/misc_info.txt.
933 misc_info_path = ['META', 'misc_info.txt']
934 vendor_misc_info_dict = common.LoadDictionaryFromFile(
935 os.path.join(vendor_meta, *misc_info_path))
936
937 if (vendor_misc_info_dict.get('building_with_vsdk') != 'true' or
Daniel Normane292f5f2022-02-17 14:16:10 -0800938 framework_dexpreopt_tools is None or framework_dexpreopt_config is None or
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700939 vendor_dexpreopt_config is None):
940 return
941
942 logger.info('applying dexpreopt')
943
944 # The directory structure to apply dexpreopt is:
945 #
946 # <temp_dir>/
947 # framework_meta/
948 # META/
949 # vendor_meta/
950 # META/
951 # output/
952 # SYSTEM/
953 # VENDOR/
954 # IMAGES/
955 # <other items extracted from system and vendor target files>
956 # tools/
957 # <contents of dexpreopt_tools.zip>
958 # system_config/
959 # <contents of system dexpreopt_config.zip>
960 # vendor_config/
961 # <contents of vendor dexpreopt_config.zip>
962 # system -> output/SYSTEM
963 # vendor -> output/VENDOR
964 # apex -> output/SYSTEM/apex (only for flattened APEX builds)
965 # apex/ (extracted updatable APEX)
966 # <apex 1>/
967 # ...
968 # <apex 2>/
969 # ...
970 # ...
971 # out/dex2oat_result/vendor/
972 # <app>
973 # oat/arm64/
974 # package.vdex
975 # package.odex
976 # <priv-app>
977 # oat/arm64/
978 # package.vdex
979 # package.odex
980 dexpreopt_tools_files_temp_dir = os.path.join(temp_dir, 'tools')
Daniel Normane292f5f2022-02-17 14:16:10 -0800981 dexpreopt_framework_config_files_temp_dir = os.path.join(
982 temp_dir, 'system_config')
983 dexpreopt_vendor_config_files_temp_dir = os.path.join(temp_dir,
984 'vendor_config')
Jose Galmes9c8f6eb2021-07-21 09:34:08 -0700985
986 extract_items(
987 target_files=OPTIONS.framework_dexpreopt_tools,
988 target_files_temp_dir=dexpreopt_tools_files_temp_dir,
989 extract_item_list=('*',))
990 extract_items(
991 target_files=OPTIONS.framework_dexpreopt_config,
992 target_files_temp_dir=dexpreopt_framework_config_files_temp_dir,
993 extract_item_list=('*',))
994 extract_items(
995 target_files=OPTIONS.vendor_dexpreopt_config,
996 target_files_temp_dir=dexpreopt_vendor_config_files_temp_dir,
997 extract_item_list=('*',))
998
Daniel Normane292f5f2022-02-17 14:16:10 -0800999 os.symlink(
1000 os.path.join(output_target_files_temp_dir, 'SYSTEM'),
1001 os.path.join(temp_dir, 'system'))
1002 os.symlink(
1003 os.path.join(output_target_files_temp_dir, 'VENDOR'),
1004 os.path.join(temp_dir, 'vendor'))
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001005
1006 # The directory structure for flatteded APEXes is:
1007 #
1008 # SYSTEM
1009 # apex
1010 # <APEX name, e.g., com.android.wifi>
1011 # apex_manifest.pb
1012 # apex_pubkey
1013 # etc/
1014 # javalib/
1015 # lib/
1016 # lib64/
1017 # priv-app/
1018 #
1019 # The directory structure for updatable APEXes is:
1020 #
1021 # SYSTEM
1022 # apex
1023 # com.android.adbd.apex
1024 # com.android.appsearch.apex
1025 # com.android.art.apex
1026 # ...
Daniel Normane292f5f2022-02-17 14:16:10 -08001027 apex_root = os.path.join(output_target_files_temp_dir, 'SYSTEM', 'apex')
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001028 framework_misc_info_dict = common.LoadDictionaryFromFile(
1029 os.path.join(framework_meta, *misc_info_path))
1030
1031 # Check for flattended versus updatable APEX.
1032 if framework_misc_info_dict.get('target_flatten_apex') == 'false':
1033 # Extract APEX.
1034 logging.info('extracting APEX')
1035
1036 apex_extract_root_dir = os.path.join(temp_dir, 'apex')
1037 os.makedirs(apex_extract_root_dir)
1038
1039 for apex in (glob.glob(os.path.join(apex_root, '*.apex')) +
1040 glob.glob(os.path.join(apex_root, '*.capex'))):
1041 logging.info(' apex: %s', apex)
1042 # deapexer is in the same directory as the merge_target_files binary extracted
1043 # from otatools.zip.
1044 apex_json_info = subprocess.check_output(['deapexer', 'info', apex])
1045 logging.info(' info: %s', apex_json_info)
1046 apex_info = json.loads(apex_json_info)
1047 apex_name = apex_info['name']
1048 logging.info(' name: %s', apex_name)
1049
1050 apex_extract_dir = os.path.join(apex_extract_root_dir, apex_name)
1051 os.makedirs(apex_extract_dir)
1052
1053 # deapexer uses debugfs_static, which is part of otatools.zip.
1054 command = [
1055 'deapexer',
1056 '--debugfs_path',
1057 'debugfs_static',
1058 'extract',
1059 apex,
1060 apex_extract_dir,
1061 ]
1062 logging.info(' running %s', command)
1063 subprocess.check_call(command)
1064 else:
1065 # Flattened APEXes don't need to be extracted since they have the necessary
1066 # directory structure.
1067 os.symlink(os.path.join(apex_root), os.path.join(temp_dir, 'apex'))
1068
1069 # Modify system config to point to the tools that have been extracted.
1070 # Absolute or .. paths are not allowed by the dexpreopt_gen tool in
1071 # dexpreopt_soong.config.
1072 dexpreopt_framework_soon_config = os.path.join(
1073 dexpreopt_framework_config_files_temp_dir, 'dexpreopt_soong.config')
1074 with open(dexpreopt_framework_soon_config, 'w') as f:
1075 dexpreopt_soong_config = {
1076 'Profman': 'tools/profman',
1077 'Dex2oat': 'tools/dex2oatd',
1078 'Aapt': 'tools/aapt2',
1079 'SoongZip': 'tools/soong_zip',
1080 'Zip2zip': 'tools/zip2zip',
1081 'ManifestCheck': 'tools/manifest_check',
1082 'ConstructContext': 'tools/construct_context',
1083 }
1084 json.dump(dexpreopt_soong_config, f)
1085
1086 # TODO(b/188179859): Make *dex location configurable to vendor or system_other.
1087 use_system_other_odex = False
1088
1089 if use_system_other_odex:
1090 dex_img = 'SYSTEM_OTHER'
1091 else:
1092 dex_img = 'VENDOR'
1093 # Open vendor_filesystem_config to append the items generated by dexopt.
1094 vendor_file_system_config = open(
Daniel Normane292f5f2022-02-17 14:16:10 -08001095 os.path.join(temp_dir, 'output', 'META',
1096 'vendor_filesystem_config.txt'), 'a')
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001097
1098 # Dexpreopt vendor apps.
1099 dexpreopt_config_suffix = '_dexpreopt.config'
Daniel Normane292f5f2022-02-17 14:16:10 -08001100 for config in glob.glob(
1101 os.path.join(dexpreopt_vendor_config_files_temp_dir,
1102 '*' + dexpreopt_config_suffix)):
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001103 app = os.path.basename(config)[:-len(dexpreopt_config_suffix)]
1104 logging.info('dexpreopt config: %s %s', config, app)
1105
1106 apk_dir = 'app'
1107 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1108 if not os.path.exists(apk_path):
1109 apk_dir = 'priv-app'
1110 apk_path = os.path.join(temp_dir, 'vendor', apk_dir, app, app + '.apk')
1111 if not os.path.exists(apk_path):
Daniel Normane292f5f2022-02-17 14:16:10 -08001112 logging.warning(
1113 'skipping dexpreopt for %s, no apk found in vendor/app '
1114 'or vendor/priv-app', app)
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001115 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',
Daniel Normane292f5f2022-02-17 14:16:10 -08001124 os.path.join(dexpreopt_framework_config_files_temp_dir,
1125 'dexpreopt.config'),
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001126 '-global_soong',
Daniel Normane292f5f2022-02-17 14:16:10 -08001127 os.path.join(dexpreopt_framework_config_files_temp_dir,
1128 'dexpreopt_soong.config'),
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001129 '-module',
1130 config,
1131 '-dexpreopt_script',
1132 'dexpreopt_app.sh',
1133 '-out_dir',
1134 'out',
1135 '-base_path',
1136 '.',
1137 '--uses_target_files',
1138 ]
1139
1140 # Run the command from temp_dir so all tool paths are its descendants.
Daniel Normane292f5f2022-02-17 14:16:10 -08001141 logging.info('running %s', command)
1142 subprocess.check_call(command, cwd=temp_dir)
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001143
1144 # Call the generated script.
1145 command = ['sh', 'dexpreopt_app.sh', apk_path]
Daniel Normane292f5f2022-02-17 14:16:10 -08001146 logging.info('running %s', command)
1147 subprocess.check_call(command, cwd=temp_dir)
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001148
1149 # Output files are in:
1150 #
1151 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.vdex
1152 # <temp_dir>/out/dex2oat_result/vendor/priv-app/<app>/oat/arm64/package.odex
1153 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.vdex
1154 # <temp_dir>/out/dex2oat_result/vendor/app/<app>/oat/arm64/package.odex
1155 #
1156 # Copy the files to their destination. The structure of system_other is:
1157 #
1158 # system_other/
1159 # system-other-odex-marker
1160 # system/
1161 # app/
1162 # <app>/oat/arm64/
1163 # <app>.odex
1164 # <app>.vdex
1165 # ...
1166 # priv-app/
1167 # <app>/oat/arm64/
1168 # <app>.odex
1169 # <app>.vdex
1170 # ...
1171
1172 # TODO(b/188179859): Support for other architectures.
1173 arch = 'arm64'
1174
Daniel Normane292f5f2022-02-17 14:16:10 -08001175 dex_destination = os.path.join(temp_dir, 'output', dex_img, apk_dir, app,
1176 'oat', arch)
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001177 os.makedirs(dex_destination)
Daniel Normane292f5f2022-02-17 14:16:10 -08001178 dex2oat_path = os.path.join(temp_dir, 'out', 'dex2oat_result', 'vendor',
1179 apk_dir, app, 'oat', arch)
1180 shutil.copy(
1181 os.path.join(dex2oat_path, 'package.vdex'),
1182 os.path.join(dex_destination, app + '.vdex'))
1183 shutil.copy(
1184 os.path.join(dex2oat_path, 'package.odex'),
1185 os.path.join(dex_destination, app + '.odex'))
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001186
1187 # Append entries to vendor_file_system_config.txt, such as:
1188 #
1189 # vendor/app/<app>/oat 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1190 # vendor/app/<app>/oat/arm64 0 2000 755 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1191 # vendor/app/<app>/oat/arm64/<app>.odex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1192 # vendor/app/<app>/oat/arm64/<app>.vdex 0 0 644 selabel=u:object_r:vendor_app_file:s0 capabilities=0x0
1193 if not use_system_other_odex:
1194 vendor_app_prefix = 'vendor/' + apk_dir + '/' + app + '/oat'
1195 selabel = 'selabel=u:object_r:vendor_app_file:s0 capabilities=0x0'
1196 vendor_file_system_config.writelines([
1197 vendor_app_prefix + ' 0 2000 755 ' + selabel + '\n',
1198 vendor_app_prefix + '/' + arch + ' 0 2000 755 ' + selabel + '\n',
Daniel Normane292f5f2022-02-17 14:16:10 -08001199 vendor_app_prefix + '/' + arch + '/' + app + '.odex 0 0 644 ' +
1200 selabel + '\n',
1201 vendor_app_prefix + '/' + arch + '/' + app + '.vdex 0 0 644 ' +
1202 selabel + '\n',
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001203 ])
1204
1205 if not use_system_other_odex:
1206 vendor_file_system_config.close()
1207 # Delete vendor.img so that it will be regenerated.
1208 # TODO(b/188179859): Rebuilding a vendor image in GRF mode (e.g., T(framework)
1209 # and S(vendor) may require logic similar to that in
1210 # rebuild_image_with_sepolicy.
Daniel Normane292f5f2022-02-17 14:16:10 -08001211 vendor_img = os.path.join(output_target_files_temp_dir, 'IMAGES',
1212 'vendor.img')
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001213 if os.path.exists(vendor_img):
1214 logging.info('Deleting %s', vendor_img)
1215 os.remove(vendor_img)
1216
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001217
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001218def create_merged_package(temp_dir, framework_target_files, framework_item_list,
1219 vendor_target_files, vendor_item_list,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001220 framework_misc_info_keys, rebuild_recovery,
1221 framework_dexpreopt_tools, framework_dexpreopt_config,
1222 vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001223 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001224
1225 Args:
1226 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -07001227 input target files packages, and also a scratch directory that we use for
1228 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001229 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001230 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001231 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001232 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -07001233 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -07001234 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -07001235 vendor_target_files: The name of the zip archive containing the vendor
1236 partial target files package.
1237 vendor_item_list: The list of items to extract from the partial vendor
1238 target files package as is, meaning these items will land in the output
1239 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -07001240 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001241 framework_misc_info_keys: A list of keys to obtain from the framework
1242 instance of META/misc_info.txt. The remaining keys should come from the
1243 vendor instance.
Daniel Normana4911da2019-03-15 14:36:21 -07001244 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -07001245 devices and write it to the system image.
Daniel Normane292f5f2022-02-17 14:16:10 -08001246 Args used if dexpreopt is applied:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001247 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1248 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1249 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
1250
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001251 Returns:
1252 Path to merged package under temp directory.
1253 """
Daniel Normandbbf5a32020-10-22 16:03:32 -07001254 # Extract "as is" items from the input framework and vendor partial target
1255 # files packages directly into the output temporary directory, since these items
1256 # do not need special case processing.
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001257
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001258 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
Bill Peckham889b0c62019-02-21 18:53:37 -08001259 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001260 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001261 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001262 extract_item_list=framework_item_list)
Bill Peckham889b0c62019-02-21 18:53:37 -08001263 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001264 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001265 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001266 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001267
Daniel Normandbbf5a32020-10-22 16:03:32 -07001268 # Perform special case processing on META/* items.
1269 # After this function completes successfully, all the files we need to create
1270 # the output target files package are in place.
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001271 framework_meta = os.path.join(temp_dir, 'framework_meta')
1272 vendor_meta = os.path.join(temp_dir, 'vendor_meta')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001273 extract_items(
1274 target_files=framework_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001275 target_files_temp_dir=framework_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001276 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001277 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001278 target_files=vendor_target_files,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001279 target_files_temp_dir=vendor_meta,
Daniel Normandbbf5a32020-10-22 16:03:32 -07001280 extract_item_list=('META/*',))
Bill Peckham889b0c62019-02-21 18:53:37 -08001281 process_special_cases(
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001282 temp_dir=temp_dir,
1283 framework_meta=framework_meta,
1284 vendor_meta=vendor_meta,
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001285 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham19c3feb2020-03-20 18:31:43 -07001286 framework_misc_info_keys=framework_misc_info_keys,
1287 framework_partition_set=item_list_to_partition_set(framework_item_list),
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001288 vendor_partition_set=item_list_to_partition_set(vendor_item_list),
1289 framework_dexpreopt_tools=framework_dexpreopt_tools,
1290 framework_dexpreopt_config=framework_dexpreopt_config,
1291 vendor_dexpreopt_config=vendor_dexpreopt_config)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001292
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001293 return output_target_files_temp_dir
1294
1295
1296def generate_images(target_files_dir, rebuild_recovery):
1297 """Generate images from target files.
1298
1299 This function takes merged output temporary directory and create images
1300 from it.
1301
1302 Args:
1303 target_files_dir: Path to merged temp directory.
1304 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1305 devices and write it to the system image.
1306 """
1307
1308 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001309
Daniel Normandbbf5a32020-10-22 16:03:32 -07001310 add_img_args = [
1311 '--verbose',
1312 '--add_missing',
1313 ]
Bill Peckhame868aec2019-09-17 17:06:47 -07001314 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -07001315 if rebuild_recovery:
1316 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001317 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001318
1319 add_img_to_target_files.main(add_img_args)
1320
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001321
Daniel Norman571e1822021-06-25 17:18:25 -07001322def rebuild_image_with_sepolicy(target_files_dir,
1323 vendor_otatools=None,
1324 vendor_target_files=None):
1325 """Rebuilds odm.img or vendor.img to include merged sepolicy files.
1326
1327 If odm is present then odm is preferred -- otherwise vendor is used.
1328
1329 Args:
1330 target_files_dir: Path to the extracted merged target-files package.
1331 vendor_otatools: If not None, path to an otatools.zip from the vendor build
1332 that is used when recompiling the image.
1333 vendor_target_files: Expected if vendor_otatools is not None. Path to the
1334 vendor target-files zip.
1335 """
1336 partition = 'vendor'
1337 if os.path.exists(os.path.join(target_files_dir, 'ODM')) or os.path.exists(
1338 os.path.join(target_files_dir, 'IMAGES/odm.img')):
1339 partition = 'odm'
1340 partition_img = '{}.img'.format(partition)
1341
1342 logger.info('Recompiling %s using the merged sepolicy files.', partition_img)
1343
1344 # Copy the combined SEPolicy file and framework hashes to the image that is
1345 # being rebuilt.
1346 def copy_selinux_file(input_path, output_filename):
Po Hu0e4403e2021-07-06 17:05:56 +08001347 input_filename = os.path.join(target_files_dir, input_path)
1348 if not os.path.exists(input_filename):
1349 input_filename = input_filename.replace('SYSTEM_EXT/', 'SYSTEM/system_ext/') \
1350 .replace('PRODUCT/', 'SYSTEM/product/')
1351 if not os.path.exists(input_filename):
1352 logger.info('Skipping copy_selinux_file for %s', input_filename)
1353 return
Daniel Norman571e1822021-06-25 17:18:25 -07001354 shutil.copy(
Po Hu0e4403e2021-07-06 17:05:56 +08001355 input_filename,
Daniel Norman571e1822021-06-25 17:18:25 -07001356 os.path.join(target_files_dir, partition.upper(), 'etc/selinux',
1357 output_filename))
1358
1359 copy_selinux_file('META/combined_sepolicy', 'precompiled_sepolicy')
1360 copy_selinux_file('SYSTEM/etc/selinux/plat_sepolicy_and_mapping.sha256',
1361 'precompiled_sepolicy.plat_sepolicy_and_mapping.sha256')
1362 copy_selinux_file(
1363 'SYSTEM_EXT/etc/selinux/system_ext_sepolicy_and_mapping.sha256',
1364 'precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256')
1365 copy_selinux_file('PRODUCT/etc/selinux/product_sepolicy_and_mapping.sha256',
1366 'precompiled_sepolicy.product_sepolicy_and_mapping.sha256')
1367
1368 if not vendor_otatools:
1369 # Remove the partition from the merged target-files archive. It will be
1370 # rebuilt later automatically by generate_images().
1371 os.remove(os.path.join(target_files_dir, 'IMAGES', partition_img))
1372 else:
1373 # TODO(b/192253131): Remove the need for vendor_otatools by fixing
1374 # backwards-compatibility issues when compiling images on R from S+.
1375 if not vendor_target_files:
1376 raise ValueError(
1377 'Expected vendor_target_files if vendor_otatools is not None.')
1378 logger.info(
1379 '%s recompilation will be performed using the vendor otatools.zip',
1380 partition_img)
1381
1382 # Unzip the vendor build's otatools.zip and target-files archive.
1383 vendor_otatools_dir = common.MakeTempDir(
1384 prefix='merge_target_files_vendor_otatools_')
1385 vendor_target_files_dir = common.MakeTempDir(
1386 prefix='merge_target_files_vendor_target_files_')
1387 common.UnzipToDir(vendor_otatools, vendor_otatools_dir)
1388 common.UnzipToDir(vendor_target_files, vendor_target_files_dir)
1389
1390 # Copy the partition contents from the merged target-files archive to the
1391 # vendor target-files archive.
1392 shutil.rmtree(os.path.join(vendor_target_files_dir, partition.upper()))
1393 shutil.copytree(
1394 os.path.join(target_files_dir, partition.upper()),
Po Hu0e4403e2021-07-06 17:05:56 +08001395 os.path.join(vendor_target_files_dir, partition.upper()),
1396 symlinks=True)
Daniel Norman571e1822021-06-25 17:18:25 -07001397
1398 # Delete then rebuild the partition.
1399 os.remove(os.path.join(vendor_target_files_dir, 'IMAGES', partition_img))
1400 rebuild_partition_command = [
1401 os.path.join(vendor_otatools_dir, 'bin', 'add_img_to_target_files'),
1402 '--verbose',
1403 '--add_missing',
1404 vendor_target_files_dir,
1405 ]
1406 logger.info('Recompiling %s: %s', partition_img,
1407 ' '.join(rebuild_partition_command))
1408 common.RunAndCheckOutput(rebuild_partition_command, verbose=True)
1409
1410 # Move the newly-created image to the merged target files dir.
Po Hu0e4403e2021-07-06 17:05:56 +08001411 if not os.path.exists(os.path.join(target_files_dir, 'IMAGES')):
1412 os.makedirs(os.path.join(target_files_dir, 'IMAGES'))
Daniel Norman571e1822021-06-25 17:18:25 -07001413 shutil.move(
1414 os.path.join(vendor_target_files_dir, 'IMAGES', partition_img),
1415 os.path.join(target_files_dir, 'IMAGES', partition_img))
1416
1417
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001418def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -07001419 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001420
1421 Args:
1422 target_dir: Path to the target file package which contains misc_info.txt for
1423 detailed information for super image.
1424 output_super_empty: If provided, copies a super_empty.img file from the
1425 target files package to this path.
1426 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001427 # Create super_empty.img using the merged misc_info.txt.
1428
Daniel Norman4cc9df62019-07-18 10:11:07 -07001429 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001430
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +09001431 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
1432 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001433
1434 if use_dynamic_partitions != 'true' and output_super_empty:
1435 raise ValueError(
1436 'Building super_empty.img requires use_dynamic_partitions=true.')
1437 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001438 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001439 build_super_image_args = [
1440 misc_info_txt,
1441 super_empty_img,
1442 ]
1443 build_super_image.main(build_super_image_args)
1444
1445 # Copy super_empty.img to the user-provided output_super_empty location.
1446 if output_super_empty:
1447 shutil.copyfile(super_empty_img, output_super_empty)
1448
Daniel Normanb8a2f9d2019-04-24 12:55:51 -07001449
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001450def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -07001451 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001452
1453 Args:
1454 output_file: The name of the zip archive target files package.
1455 source_dir: The target directory contains package to be archived.
1456 temp_dir: Path to temporary directory for any intermediate files.
1457 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001458 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001459 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001460 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001461
Daniel Normandbbf5a32020-10-22 16:03:32 -07001462 def files_from_path(target_path, extra_args=None):
1463 """Gets files under the given path and return a sorted list."""
1464 find_command = ['find', target_path] + (extra_args or [])
1465 find_process = common.Run(
1466 find_command, stdout=subprocess.PIPE, verbose=False)
1467 return common.RunAndCheckOutput(['sort'],
1468 stdin=find_process.stdout,
1469 verbose=False)
1470
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001471 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -07001472 other_content = files_from_path(
1473 source_dir,
1474 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001475
Tao Bao2ad4b822019-06-27 16:52:12 -07001476 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001477 f.write(meta_content)
1478 f.write(other_content)
1479
1480 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -08001481 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001482 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -07001483 '-o',
1484 output_zip,
1485 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001486 source_dir,
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001487 '-r',
Daniel Normane5b134a2019-04-17 14:54:06 -07001488 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001489 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001490
1491 logger.info('creating %s', output_file)
Daniel Normaneaf5c1d2021-02-09 11:01:42 -08001492 common.RunAndCheckOutput(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001493 logger.info('finished creating %s', output_file)
1494
1495 return output_zip
1496
1497
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001498def merge_target_files(temp_dir, framework_target_files, framework_item_list,
1499 framework_misc_info_keys, vendor_target_files,
1500 vendor_item_list, output_target_files, output_dir,
1501 output_item_list, output_ota, output_img,
Daniel Norman571e1822021-06-25 17:18:25 -07001502 output_super_empty, rebuild_recovery, vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001503 rebuild_sepolicy, framework_dexpreopt_tools,
1504 framework_dexpreopt_config, vendor_dexpreopt_config):
Tao Bao2ad4b822019-06-27 16:52:12 -07001505 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001506
1507 This function takes framework and vendor target files packages as input,
1508 performs various file extractions, special case processing, and finally
1509 creates a merged zip archive as output.
1510
1511 Args:
1512 temp_dir: The name of a directory we use when we extract items from the
1513 input target files packages, and also a scratch directory that we use for
1514 temporary files.
1515 framework_target_files: The name of the zip archive containing the framework
1516 partial target files package.
1517 framework_item_list: The list of items to extract from the partial framework
1518 target files package as is, meaning these items will land in the output
1519 target files package exactly as they appear in the input partial framework
1520 target files package.
Daniel Normandbbf5a32020-10-22 16:03:32 -07001521 framework_misc_info_keys: A list of keys to obtain from the framework
1522 instance of META/misc_info.txt. The remaining keys should come from the
1523 vendor instance.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001524 vendor_target_files: The name of the zip archive containing the vendor
1525 partial target files package.
1526 vendor_item_list: The list of items to extract from the partial vendor
1527 target files package as is, meaning these items will land in the output
1528 target files package exactly as they appear in the input partial vendor
1529 target files package.
1530 output_target_files: The name of the output zip archive target files package
1531 created by merging framework and vendor.
1532 output_dir: The destination directory for saving merged files.
1533 output_item_list: The list of items to copy into the output_dir.
1534 output_ota: The name of the output zip archive ota package.
1535 output_img: The name of the output zip archive img package.
1536 output_super_empty: If provided, creates a super_empty.img file from the
1537 merged target files package and saves it at this path.
1538 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
1539 devices and write it to the system image.
Daniel Norman571e1822021-06-25 17:18:25 -07001540 vendor_otatools: Path to an otatools zip used for recompiling vendor images.
1541 rebuild_sepolicy: If true, rebuild odm.img (if target uses ODM) or
1542 vendor.img using a merged precompiled_sepolicy file.
Daniel Normane292f5f2022-02-17 14:16:10 -08001543 Args used if dexpreopt is applied:
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001544 framework_dexpreopt_tools: Location of dexpreopt_tools.zip.
1545 framework_dexpreopt_config: Location of framework's dexpreopt_config.zip.
1546 vendor_dexpreopt_config: Location of vendor's dexpreopt_config.zip.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001547 """
1548
1549 logger.info('starting: merge framework %s and vendor %s into output %s',
1550 framework_target_files, vendor_target_files, output_target_files)
1551
1552 output_target_files_temp_dir = create_merged_package(
1553 temp_dir, framework_target_files, framework_item_list,
1554 vendor_target_files, vendor_item_list, framework_misc_info_keys,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001555 rebuild_recovery, framework_dexpreopt_tools, framework_dexpreopt_config,
1556 vendor_dexpreopt_config)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001557
Yifan Hongade0d3f2019-08-21 16:37:11 -07001558 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
Daniel Normanb0c75912020-09-24 14:30:21 -07001559 raise RuntimeError('Incompatible VINTF metadata')
Yifan Hongade0d3f2019-08-21 16:37:11 -07001560
Daniel Norman21c34f72020-11-11 17:25:50 -08001561 partition_map = common.PartitionMapFromTargetFiles(
1562 output_target_files_temp_dir)
1563
Daniel Normand3351562020-10-29 12:33:11 -07001564 # Generate and check for cross-partition violations of sharedUserId
1565 # values in APKs. This requires the input target-files packages to contain
1566 # *.apk files.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001567 shareduid_violation_modules = os.path.join(
1568 output_target_files_temp_dir, 'META', 'shareduid_violation_modules.json')
1569 with open(shareduid_violation_modules, 'w') as f:
Daniel Normanb8d52a22020-10-26 17:55:00 -07001570 violation = find_shareduid_violation.FindShareduidViolation(
1571 output_target_files_temp_dir, partition_map)
Daniel Normand3351562020-10-29 12:33:11 -07001572
1573 # Write the output to a file to enable debugging.
Daniel Normanb8d52a22020-10-26 17:55:00 -07001574 f.write(violation)
Daniel Normand3351562020-10-29 12:33:11 -07001575
1576 # Check for violations across the input builds' partition groups.
Daniel Norman21c34f72020-11-11 17:25:50 -08001577 framework_partitions = item_list_to_partition_set(framework_item_list)
1578 vendor_partitions = item_list_to_partition_set(vendor_item_list)
Daniel Normand3351562020-10-29 12:33:11 -07001579 shareduid_errors = common.SharedUidPartitionViolations(
1580 json.loads(violation), [framework_partitions, vendor_partitions])
1581 if shareduid_errors:
1582 for error in shareduid_errors:
1583 logger.error(error)
1584 raise ValueError('sharedUserId APK error. See %s' %
1585 shareduid_violation_modules)
Daniel Normanb8d52a22020-10-26 17:55:00 -07001586
Daniel Norman48603ff2021-02-22 15:15:24 -08001587 # host_init_verifier and secilc check only the following partitions:
Daniel Norman21c34f72020-11-11 17:25:50 -08001588 filtered_partitions = {
1589 partition: path
1590 for partition, path in partition_map.items()
Daniel Norman21c34f72020-11-11 17:25:50 -08001591 if partition in ['system', 'system_ext', 'product', 'vendor', 'odm']
1592 }
Daniel Norman48603ff2021-02-22 15:15:24 -08001593
1594 # Run host_init_verifier on the combined init rc files.
Daniel Norman21c34f72020-11-11 17:25:50 -08001595 common.RunHostInitVerifier(
1596 product_out=output_target_files_temp_dir,
1597 partition_map=filtered_partitions)
1598
Daniel Norman48603ff2021-02-22 15:15:24 -08001599 # Check that the split sepolicy from the multiple builds can compile.
Daniel Norman571e1822021-06-25 17:18:25 -07001600 split_sepolicy_cmd = compile_split_sepolicy(output_target_files_temp_dir,
1601 filtered_partitions)
Daniel Norman48603ff2021-02-22 15:15:24 -08001602 logger.info('Compiling split sepolicy: %s', ' '.join(split_sepolicy_cmd))
1603 common.RunAndCheckOutput(split_sepolicy_cmd)
Daniel Norman571e1822021-06-25 17:18:25 -07001604 # Include the compiled policy in an image if requested.
1605 if rebuild_sepolicy:
1606 rebuild_image_with_sepolicy(output_target_files_temp_dir, vendor_otatools,
1607 vendor_target_files)
Daniel Norman48603ff2021-02-22 15:15:24 -08001608
Daniel Normane9af70a2021-04-15 16:39:22 -07001609 # Run validation checks on the pre-installed APEX files.
1610 validate_merged_apex_info(output_target_files_temp_dir, partition_map.keys())
1611
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001612 generate_images(output_target_files_temp_dir, rebuild_recovery)
1613
1614 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
1615
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001616 # Finally, create the output target files zip archive and/or copy the
1617 # output items to the output target files directory.
1618
1619 if output_dir:
1620 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
1621
1622 if not output_target_files:
1623 return
1624
Iavor-Valentin Iftimeb837b712022-01-27 16:29:37 +00001625 # Create the merged META/care_map.pb if A/B update
1626 if 'ab_update' in framework_misc_info_keys:
1627 generate_care_map(partition_map.keys(), output_target_files_temp_dir)
Daniel Normandb8cacc2021-04-09 15:34:43 -07001628
Kiyoung Kim7cbeda72019-06-28 13:26:04 +09001629 output_zip = create_target_files_archive(output_target_files,
1630 output_target_files_temp_dir,
1631 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001632
Daniel Norman74eb74b2019-09-18 14:01:48 -07001633 # Create the IMG package from the merged target files package.
Daniel Norman74eb74b2019-09-18 14:01:48 -07001634 if output_img:
1635 img_from_target_files.main([output_zip, output_img])
1636
Daniel Norman3b64ce12019-04-16 16:11:35 -07001637 # Create the OTA package from the merged target files package.
1638
1639 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001640 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -07001641
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001642
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001643def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -07001644 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001645
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001646 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001647 directory. It also cleans up the temporary directory.
1648
1649 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -07001650 func: The function to call. Should accept one parameter, the path to the
1651 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001652 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001653 """
1654
1655 # Create a temporary directory. This will serve as the parent of directories
1656 # we use when we extract items from the input target files packages, and also
1657 # a scratch directory that we use for temporary files.
1658
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001659 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
1660
1661 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001662 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001663 finally:
1664 if keep_tmp:
1665 logger.info('keeping %s', temp_dir)
1666 else:
1667 common.Cleanup()
1668
1669
1670def main():
1671 """The main function.
1672
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001673 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001674 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001675 """
1676
1677 common.InitLogging()
1678
Bill Peckhamf753e152019-02-19 18:02:46 -08001679 def option_handler(o, a):
1680 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001681 logger.warning(
1682 '--system-target-files has been renamed to --framework-target-files')
1683 OPTIONS.framework_target_files = a
1684 elif o == '--framework-target-files':
1685 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001686 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001687 logger.warning(
1688 '--system-item-list has been renamed to --framework-item-list')
1689 OPTIONS.framework_item_list = a
1690 elif o == '--framework-item-list':
1691 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001692 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -07001693 logger.warning('--system-misc-info-keys has been renamed to '
1694 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001695 OPTIONS.framework_misc_info_keys = a
1696 elif o == '--framework-misc-info-keys':
1697 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001698 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001699 logger.warning(
1700 '--other-target-files has been renamed to --vendor-target-files')
1701 OPTIONS.vendor_target_files = a
1702 elif o == '--vendor-target-files':
1703 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001704 elif o == '--other-item-list':
Daniel Norman2d7989a2021-04-05 17:40:47 +00001705 logger.warning('--other-item-list has been renamed to --vendor-item-list')
Daniel Normand5d70ea2019-06-05 15:13:43 -07001706 OPTIONS.vendor_item_list = a
1707 elif o == '--vendor-item-list':
1708 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001709 elif o == '--output-target-files':
1710 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001711 elif o == '--output-dir':
1712 OPTIONS.output_dir = a
1713 elif o == '--output-item-list':
1714 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001715 elif o == '--output-ota':
1716 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001717 elif o == '--output-img':
1718 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001719 elif o == '--output-super-empty':
1720 OPTIONS.output_super_empty = a
Daniel Normanb0c75912020-09-24 14:30:21 -07001721 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -07001722 OPTIONS.rebuild_recovery = True
Daniel Normanb0c75912020-09-24 14:30:21 -07001723 elif o == '--allow-duplicate-apkapex-keys':
1724 OPTIONS.allow_duplicate_apkapex_keys = True
Daniel Norman571e1822021-06-25 17:18:25 -07001725 elif o == '--vendor-otatools':
1726 OPTIONS.vendor_otatools = a
1727 elif o == '--rebuild-sepolicy':
1728 OPTIONS.rebuild_sepolicy = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001729 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001730 OPTIONS.keep_tmp = True
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001731 elif o == '--framework-dexpreopt-config':
1732 OPTIONS.framework_dexpreopt_config = a
1733 elif o == '--framework-dexpreopt-tools':
1734 OPTIONS.framework_dexpreopt_tools = a
1735 elif o == '--vendor-dexpreopt-config':
1736 OPTIONS.vendor_dexpreopt_config = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001737 else:
1738 return False
1739 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001740
Bill Peckhamf753e152019-02-19 18:02:46 -08001741 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001742 sys.argv[1:],
1743 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001744 extra_long_opts=[
1745 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001746 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001747 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001748 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001749 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001750 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001751 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001752 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001753 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001754 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001755 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001756 'output-dir=',
1757 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001758 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001759 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001760 'output-super-empty=',
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001761 'framework-dexpreopt-config=',
1762 'framework-dexpreopt-tools=',
1763 'vendor-dexpreopt-config=',
Daniel Normana4911da2019-03-15 14:36:21 -07001764 'rebuild_recovery',
Daniel Normanb0c75912020-09-24 14:30:21 -07001765 'allow-duplicate-apkapex-keys',
Daniel Norman571e1822021-06-25 17:18:25 -07001766 'vendor-otatools=',
1767 'rebuild-sepolicy',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001768 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001769 ],
1770 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001771
Tao Bao2ad4b822019-06-27 16:52:12 -07001772 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001773 if (args or OPTIONS.framework_target_files is None or
1774 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001775 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
Daniel Norman2d7989a2021-04-05 17:40:47 +00001776 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001777 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001778 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001779
Daniel Normand5d70ea2019-06-05 15:13:43 -07001780 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001781 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001782 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001783 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001784
Daniel Normand5d70ea2019-06-05 15:13:43 -07001785 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001786 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001787 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001788 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001789 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001790
Daniel Normand5d70ea2019-06-05 15:13:43 -07001791 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001792 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001793 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001794 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001795
Daniel Normanfdb38812019-04-15 09:47:24 -07001796 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001797 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001798 else:
1799 output_item_list = None
1800
Daniel Normane5964522019-03-19 10:32:03 -07001801 if not validate_config_lists(
Daniel Norman2d7989a2021-04-05 17:40:47 +00001802 framework_item_list=framework_item_list,
1803 framework_misc_info_keys=framework_misc_info_keys,
1804 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001805 sys.exit(1)
1806
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001807 call_func_with_temp_dir(
1808 lambda temp_dir: merge_target_files(
1809 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001810 framework_target_files=OPTIONS.framework_target_files,
1811 framework_item_list=framework_item_list,
1812 framework_misc_info_keys=framework_misc_info_keys,
1813 vendor_target_files=OPTIONS.vendor_target_files,
1814 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001815 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001816 output_dir=OPTIONS.output_dir,
1817 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001818 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001819 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001820 output_super_empty=OPTIONS.output_super_empty,
Daniel Norman571e1822021-06-25 17:18:25 -07001821 rebuild_recovery=OPTIONS.rebuild_recovery,
1822 vendor_otatools=OPTIONS.vendor_otatools,
Jose Galmes9c8f6eb2021-07-21 09:34:08 -07001823 rebuild_sepolicy=OPTIONS.rebuild_sepolicy,
1824 framework_dexpreopt_tools=OPTIONS.framework_dexpreopt_tools,
1825 framework_dexpreopt_config=OPTIONS.framework_dexpreopt_config,
Daniel Normane292f5f2022-02-17 14:16:10 -08001826 vendor_dexpreopt_config=OPTIONS.vendor_dexpreopt_config),
1827 OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001828
1829
1830if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001831 main()