blob: 544f996f99f1d36eb973eaf70a3b204dcdaca41e [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 Normand5d70ea2019-06-05 15:13:43 -070019One package contains framework files, and the other contains vendor files.
Daniel Normane5b134a2019-04-17 14:54:06 -070020It produces a complete target files package that can be used to generate an
21OTA package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080022
23Usage: merge_target_files.py [args]
24
Daniel Normand5d70ea2019-06-05 15:13:43 -070025 --framework-target-files framework-target-files-zip-archive
26 The input target files package containing framework bits. This is a zip
Bill Peckhame9eb5f92019-02-01 15:52:10 -080027 archive.
28
Daniel Normand5d70ea2019-06-05 15:13:43 -070029 --framework-item-list framework-item-list-file
Daniel Norman2c99c5b2019-03-07 13:01:48 -080030 The optional path to a newline-separated config file that replaces the
Daniel Normand5d70ea2019-06-05 15:13:43 -070031 contents of DEFAULT_FRAMEWORK_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080032
Daniel Normand5d70ea2019-06-05 15:13:43 -070033 --framework-misc-info-keys framework-misc-info-keys-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_MISC_INFO_KEYS if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080036
Daniel Normand5d70ea2019-06-05 15:13:43 -070037 --vendor-target-files vendor-target-files-zip-archive
38 The input target files package containing vendor bits. This is a zip
Bill Peckhame9eb5f92019-02-01 15:52:10 -080039 archive.
40
Daniel Normand5d70ea2019-06-05 15:13:43 -070041 --vendor-item-list vendor-item-list-file
Daniel Norman2c99c5b2019-03-07 13:01:48 -080042 The optional path to a newline-separated config file that replaces the
Daniel Normand5d70ea2019-06-05 15:13:43 -070043 contents of DEFAULT_VENDOR_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080044
Bill Peckhame9eb5f92019-02-01 15:52:10 -080045 --output-target-files output-target-files-package
Daniel Normanfdb38812019-04-15 09:47:24 -070046 If provided, the output merged target files package. Also a zip archive.
47
48 --output-dir output-directory
49 If provided, the destination directory for saving merged files. Requires
50 the --output-item-list flag.
51 Can be provided alongside --output-target-files, or by itself.
52
53 --output-item-list output-item-list-file.
54 The optional path to a newline-separated config file that specifies the
55 file patterns to copy into the --output-dir. Required if providing
56 the --output-dir flag.
Daniel Normana4911da2019-03-15 14:36:21 -070057
Daniel Norman3b64ce12019-04-16 16:11:35 -070058 --output-ota output-ota-package
59 The output ota package. This is a zip archive. Use of this flag may
60 require passing the --path common flag; see common.py.
61
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070062 --output-img output-img-package
63 The output img package, suitable for use with 'fastboot update'. Use of
64 this flag may require passing the --path common flag; see common.py.
65
Daniel Normanf0318252019-04-15 11:34:56 -070066 --output-super-empty output-super-empty-image
67 If provided, creates a super_empty.img file from the merged target
68 files package and saves it at this path.
69
Daniel Normana4911da2019-03-15 14:36:21 -070070 --rebuild_recovery
Bill Peckhame868aec2019-09-17 17:06:47 -070071 Deprecated; does nothing.
Bill Peckham364c1cc2019-03-29 18:27:23 -070072
73 --keep-tmp
74 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080075"""
76
77from __future__ import print_function
78
Bill Peckhame9eb5f92019-02-01 15:52:10 -080079import fnmatch
80import logging
81import os
Daniel Normanfdb38812019-04-15 09:47:24 -070082import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -070083import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -080084import sys
85import zipfile
86
Bill Peckhame9eb5f92019-02-01 15:52:10 -080087import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070088import build_super_image
Yifan Hongade0d3f2019-08-21 16:37:11 -070089import check_target_files_vintf
Daniel Normanf0318252019-04-15 11:34:56 -070090import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070091import img_from_target_files
Daniel Norman3b64ce12019-04-16 16:11:35 -070092import ota_from_target_files
Bill Peckhame9eb5f92019-02-01 15:52:10 -080093
94logger = logging.getLogger(__name__)
Tao Bao2ad4b822019-06-27 16:52:12 -070095
Bill Peckhame9eb5f92019-02-01 15:52:10 -080096OPTIONS = common.OPTIONS
Daniel Normand5d70ea2019-06-05 15:13:43 -070097OPTIONS.framework_target_files = None
98OPTIONS.framework_item_list = None
99OPTIONS.framework_misc_info_keys = None
100OPTIONS.vendor_target_files = None
101OPTIONS.vendor_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800102OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700103OPTIONS.output_dir = None
104OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700105OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700106OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700107OPTIONS.output_super_empty = None
Bill Peckhame868aec2019-09-17 17:06:47 -0700108# TODO(b/132730255): Remove this option.
Daniel Normana4911da2019-03-15 14:36:21 -0700109OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800110OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800111
Daniel Normand5d70ea2019-06-05 15:13:43 -0700112# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
113# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800114# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700115# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800116
Daniel Normand5d70ea2019-06-05 15:13:43 -0700117DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800118 'META/apkcerts.txt',
119 'META/filesystem_config.txt',
120 'META/root_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800121 'META/update_engine_config.txt',
122 'PRODUCT/*',
123 'ROOT/*',
124 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700125)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800126
Daniel Normand5d70ea2019-06-05 15:13:43 -0700127# FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
128# partial framework target files package that need some special processing, such
129# as some sort of combination with items from the partial vendor target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800130# package.
131
Daniel Normand5d70ea2019-06-05 15:13:43 -0700132FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800133
Daniel Normand5d70ea2019-06-05 15:13:43 -0700134# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
135# framework instance of META/misc_info.txt. The remaining keys from the
136# vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800137
Daniel Normand5d70ea2019-06-05 15:13:43 -0700138DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800139 'avb_system_hashtree_enable',
140 'avb_system_add_hashtree_footer_args',
141 'avb_system_key_path',
142 'avb_system_algorithm',
143 'avb_system_rollback_index_location',
144 'avb_product_hashtree_enable',
145 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900146 'avb_system_ext_hashtree_enable',
147 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800148 'system_root_image',
149 'root_dir',
150 'ab_update',
151 'default_system_dev_certificate',
152 'system_size',
Daniel Normanedf12472019-05-22 10:47:08 -0700153)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800154
Daniel Normand5d70ea2019-06-05 15:13:43 -0700155# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
156# vendor target files package as is, meaning these items will land in the output
157# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800158# files package.
159
Daniel Normand5d70ea2019-06-05 15:13:43 -0700160DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800161 'META/boot_filesystem_config.txt',
162 'META/otakeys.txt',
163 'META/releasetools.py',
164 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800165 'BOOT/*',
166 'DATA/*',
167 'ODM/*',
168 'OTA/android-info.txt',
169 'PREBUILT_IMAGES/*',
170 'RADIO/*',
171 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700172)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800173
Daniel Normand5d70ea2019-06-05 15:13:43 -0700174# VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
175# partial vendor target files package that need some special processing, such as
176# some sort of combination with items from the partial framework target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800177# package.
178
Daniel Normand5d70ea2019-06-05 15:13:43 -0700179VENDOR_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Daniel Normanedf12472019-05-22 10:47:08 -0700180
181# The merge config lists should not attempt to extract items from both
182# builds for any of the following partitions. The partitions in
183# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700184# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700185
186SINGLE_BUILD_PARTITIONS = (
187 'BOOT/',
188 'DATA/',
189 'ODM/',
190 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900191 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700192 'RADIO/',
193 'RECOVERY/',
194 'ROOT/',
195 'SYSTEM/',
196 'SYSTEM_OTHER/',
197 'VENDOR/',
198)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800199
200
Chris Grossfabf50a2019-05-02 12:42:09 -0700201def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700202 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700203
Tao Bao2ad4b822019-06-27 16:52:12 -0700204 This function sorts the contents of the list or dict and then writes the
205 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700206
207 Args:
208 data: The list or dict to sort and write.
209 path: Path to the file to write the sorted values to. The file at path will
210 be overridden if it exists.
211 """
212 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700213 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700214 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
215 data, dict) else '{}\n'.format(entry)
216 output.write(out_str)
217
218
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800219def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700220 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800221
222 This function extracts from the specified target files zip archive into the
223 specified temporary directory, the items specified in the extract item list.
224
225 Args:
226 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800227 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700228 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800229 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800230 """
231
232 logger.info('extracting from %s', target_files)
233
234 # Filter the extract_item_list to remove any items that do not exist in the
235 # zip file. Otherwise, the extraction step will fail.
236
Daniel Norman4cc9df62019-07-18 10:11:07 -0700237 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800238 target_files_namelist = target_files_zipfile.namelist()
239
240 filtered_extract_item_list = []
241 for pattern in extract_item_list:
242 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
243 if not matching_namelist:
244 logger.warning('no match for %s', pattern)
245 else:
246 filtered_extract_item_list.append(pattern)
247
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800248 # Extract from target_files into target_files_temp_dir the
249 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800250
Daniel Normane5b134a2019-04-17 14:54:06 -0700251 common.UnzipToDir(target_files, target_files_temp_dir,
252 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800253
254
Daniel Normanfdb38812019-04-15 09:47:24 -0700255def copy_items(from_dir, to_dir, patterns):
256 """Similar to extract_items() except uses an input dir instead of zip."""
257 file_paths = []
258 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700259 file_paths.extend(
260 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
261 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700262
263 filtered_file_paths = set()
264 for pattern in patterns:
265 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
266
267 for file_path in filtered_file_paths:
268 original_file_path = os.path.join(from_dir, file_path)
269 copied_file_path = os.path.join(to_dir, file_path)
270 copied_file_dir = os.path.dirname(copied_file_path)
271 if not os.path.exists(copied_file_dir):
272 os.makedirs(copied_file_dir)
273 if os.path.islink(original_file_path):
274 os.symlink(os.readlink(original_file_path), copied_file_path)
275 else:
276 shutil.copyfile(original_file_path, copied_file_path)
277
278
Daniel Normand5d70ea2019-06-05 15:13:43 -0700279def validate_config_lists(framework_item_list, framework_misc_info_keys,
280 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700281 """Performs validations on the merge config lists.
282
283 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700284 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700285 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700286 framework_misc_info_keys: A list of keys to obtain from the framework
287 instance of META/misc_info.txt. The remaining keys from the vendor
288 instance.
289 vendor_item_list: The list of items to extract from the partial vendor
290 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700291
292 Returns:
293 False if a validation fails, otherwise true.
294 """
Daniel Normanedf12472019-05-22 10:47:08 -0700295 has_error = False
296
Daniel Normand5d70ea2019-06-05 15:13:43 -0700297 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
298 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700299
Daniel Normand5d70ea2019-06-05 15:13:43 -0700300 combined_item_set = set(framework_item_list)
301 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700302
303 # Check that the merge config lists are not missing any item specified
304 # by the default config lists.
305 difference = default_combined_item_set.difference(combined_item_set)
306 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700307 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700308 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700309 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700310 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700311 has_error = True
312
313 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700314 in_framework = any(
315 item.startswith(partition) for item in framework_item_list)
316 in_vendor = any(item.startswith(partition) for item in vendor_item_list)
317 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700318 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700319 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900320 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700321 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700322 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700323
Daniel Normand5d70ea2019-06-05 15:13:43 -0700324 if ('dynamic_partition_list' in framework_misc_info_keys) or (
325 'super_partition_groups' in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700326 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700327 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700328 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700329
Daniel Normanedf12472019-05-22 10:47:08 -0700330 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700331
332
Daniel Normand5d70ea2019-06-05 15:13:43 -0700333def process_ab_partitions_txt(framework_target_files_temp_dir,
334 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700335 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700336 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800337
Tao Bao2ad4b822019-06-27 16:52:12 -0700338 This function merges the contents of the META/ab_partitions.txt files from the
339 framework directory and the vendor directory, placing the merged result in the
340 output directory. The precondition in that the files are already extracted.
341 The post condition is that the output META/ab_partitions.txt contains the
342 merged content. The format for each ab_partitions.txt a one partition name per
343 line. The output file contains the union of the parition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800344
345 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700346 framework_target_files_temp_dir: The name of a directory containing the
347 special items extracted from the framework target files package.
348 vendor_target_files_temp_dir: The name of a directory containing the special
349 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700350 output_target_files_temp_dir: The name of a directory that will be used to
351 create the output target files package after all the special cases are
352 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800353 """
354
Daniel Normand5d70ea2019-06-05 15:13:43 -0700355 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
356 'META', 'ab_partitions.txt')
357
358 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700359 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800360
Daniel Normand5d70ea2019-06-05 15:13:43 -0700361 with open(framework_ab_partitions_txt) as f:
362 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800363
Daniel Normand5d70ea2019-06-05 15:13:43 -0700364 with open(vendor_ab_partitions_txt) as f:
365 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800366
Daniel Normand5d70ea2019-06-05 15:13:43 -0700367 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800368
Daniel Normane5b134a2019-04-17 14:54:06 -0700369 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
370 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800371
Chris Grossfabf50a2019-05-02 12:42:09 -0700372 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800373
374
Daniel Normand5d70ea2019-06-05 15:13:43 -0700375def process_misc_info_txt(framework_target_files_temp_dir,
376 vendor_target_files_temp_dir,
377 output_target_files_temp_dir,
378 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700379 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800380
381 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700382 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800383 output directory. The precondition in that the files are already extracted.
384 The post condition is that the output META/misc_info.txt contains the merged
385 content.
386
387 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700388 framework_target_files_temp_dir: The name of a directory containing the
389 special items extracted from the framework target files package.
390 vendor_target_files_temp_dir: The name of a directory containing the special
391 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700392 output_target_files_temp_dir: The name of a directory that will be used to
393 create the output target files package after all the special cases are
394 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700395 framework_misc_info_keys: A list of keys to obtain from the framework
396 instance of META/misc_info.txt. The remaining keys from the vendor
397 instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800398 """
399
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900400 misc_info_path = ['META', 'misc_info.txt']
401 framework_dict = common.LoadDictionaryFromFile(
402 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800403
Daniel Normand5d70ea2019-06-05 15:13:43 -0700404 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800405
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900406 merged_dict = common.LoadDictionaryFromFile(
407 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800408
Daniel Normand5d70ea2019-06-05 15:13:43 -0700409 # Replace certain values in merged_dict with values from
410 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800411
Daniel Normand5d70ea2019-06-05 15:13:43 -0700412 for key in framework_misc_info_keys:
413 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800414
Daniel Norman19b9fe92019-03-19 14:48:02 -0700415 # Merge misc info keys used for Dynamic Partitions.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700416 if (merged_dict.get('use_dynamic_partitions') == 'true') and (
417 framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700418 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700419 framework_dict=framework_dict,
420 vendor_dict=merged_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700421 size_prefix='super_',
422 size_suffix='_group_size',
423 list_prefix='super_',
424 list_suffix='_partition_list')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700425 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700426 # Ensure that add_img_to_target_files rebuilds super split images for
427 # devices that retrofit dynamic partitions. This flag may have been set to
428 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700429 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700430
Daniel Normand5d70ea2019-06-05 15:13:43 -0700431 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700432 # depending on which dictionary the key came from.
433 # Only the file basename is required because all selinux_fc properties are
434 # replaced with the full path to the file under META/ when misc_info.txt is
435 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700436 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700437 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700438 merged_dict[key] = 'vendor_file_contexts.bin'
439 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700440 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700441 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700442
Daniel Normane5b134a2019-04-17 14:54:06 -0700443 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
444 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700445 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800446
447
Daniel Normand5d70ea2019-06-05 15:13:43 -0700448def process_dynamic_partitions_info_txt(framework_target_files_dir,
449 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700450 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700451 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700452
453 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700454 files from the framework directory and the vendor directory, placing the
455 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700456
Daniel Normand5d70ea2019-06-05 15:13:43 -0700457 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700458 directory does not exist.
459
460 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700461 framework_target_files_dir: The name of a directory containing the special
462 items extracted from the framework target files package.
463 vendor_target_files_dir: The name of a directory containing the special
464 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700465 output_target_files_dir: The name of a directory that will be used to create
466 the output target files package after all the special cases are processed.
467 """
468
469 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700470 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700471 'dynamic_partitions_info.txt')):
472 return
473
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900474 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700475
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900476 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
477 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
478 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
479 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700480
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700481 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700482 framework_dict=framework_dynamic_partitions_dict,
483 vendor_dict=vendor_dynamic_partitions_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700484 # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
485 include_dynamic_partition_list=False,
486 size_suffix='_size',
487 list_suffix='_partition_list')
488
489 output_dynamic_partitions_info_txt = os.path.join(
490 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700491 write_sorted_data(
492 data=merged_dynamic_partitions_dict,
493 path=output_dynamic_partitions_info_txt)
494
495
Daniel Normand5d70ea2019-06-05 15:13:43 -0700496def process_apex_keys_apk_certs_common(framework_target_files_dir,
497 vendor_target_files_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700498 output_target_files_dir, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700499 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700500
501 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700502 META/apkcerts.txt files from the framework directory and the vendor directory,
503 placing the merged result in the output directory. The precondition in that
504 the files are already extracted. The post condition is that the output
505 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700506
507 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700508 framework_target_files_dir: The name of a directory containing the special
509 items extracted from the framework target files package.
510 vendor_target_files_dir: The name of a directory containing the special
511 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700512 output_target_files_dir: The name of a directory that will be used to create
513 the output target files package after all the special cases are processed.
514 file_name: The name of the file to merge. One of apkcerts.txt or
515 apexkeys.txt.
516 """
517
518 def read_helper(d):
519 temp = {}
520 file_path = os.path.join(d, 'META', file_name)
521 with open(file_path) as f:
522 for line in f:
523 if line.strip():
524 temp[line.split()[0]] = line.strip()
525 return temp
526
Daniel Normand5d70ea2019-06-05 15:13:43 -0700527 framework_dict = read_helper(framework_target_files_dir)
528 vendor_dict = read_helper(vendor_target_files_dir)
Chris Grossfabf50a2019-05-02 12:42:09 -0700529
Daniel Normand5d70ea2019-06-05 15:13:43 -0700530 for key in framework_dict:
531 if key in vendor_dict and vendor_dict[key] != framework_dict[key]:
Chris Grossfabf50a2019-05-02 12:42:09 -0700532 raise ValueError('Conflicting entries found in %s:\n %s and\n %s' %
Daniel Normand5d70ea2019-06-05 15:13:43 -0700533 (file_name, framework_dict[key], vendor_dict[key]))
534 vendor_dict[key] = framework_dict[key]
Chris Grossfabf50a2019-05-02 12:42:09 -0700535
536 output_file = os.path.join(output_target_files_dir, 'META', file_name)
537
Daniel Normand5d70ea2019-06-05 15:13:43 -0700538 write_sorted_data(data=vendor_dict.values(), path=output_file)
Daniel Normana61cde02019-05-03 14:19:13 -0700539
540
Daniel Normand5d70ea2019-06-05 15:13:43 -0700541def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700542 output_target_files_dir):
543 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700544 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
545 'framework_file_contexts.bin')
546 if not os.path.exists(framework_fc_path):
547 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
548 'file_contexts.bin')
549 if not os.path.exists(framework_fc_path):
550 raise ValueError('Missing framework file_contexts.bin.')
551 shutil.copyfile(
552 framework_fc_path,
553 os.path.join(output_target_files_dir, 'META',
554 'framework_file_contexts.bin'))
555
556 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
557 'vendor_file_contexts.bin')
558 if not os.path.exists(vendor_fc_path):
559 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700560 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700561 if not os.path.exists(vendor_fc_path):
562 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700563 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700564 vendor_fc_path,
565 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700566
567
Daniel Normand5d70ea2019-06-05 15:13:43 -0700568def process_special_cases(framework_target_files_temp_dir,
569 vendor_target_files_temp_dir,
570 output_target_files_temp_dir,
Bill Peckhame868aec2019-09-17 17:06:47 -0700571 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700572 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800573
574 Certain files in the output target files package require special-case
575 processing. This function performs all that special-case processing.
576
577 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700578 framework_target_files_temp_dir: The name of a directory containing the
579 special items extracted from the framework target files package.
580 vendor_target_files_temp_dir: The name of a directory containing the special
581 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700582 output_target_files_temp_dir: The name of a directory that will be used to
583 create the output target files package after all the special cases are
584 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700585 framework_misc_info_keys: A list of keys to obtain from the framework
586 instance of META/misc_info.txt. The remaining keys from the vendor
587 instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800588 """
589
Daniel Normand5d70ea2019-06-05 15:13:43 -0700590 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700591 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700592 framework_target_files_temp_dir=framework_target_files_temp_dir,
593 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700594 output_target_files_temp_dir=output_target_files_temp_dir)
595
Daniel Norman72c626f2019-05-13 15:58:14 -0700596 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700597 framework_target_files_dir=framework_target_files_temp_dir,
598 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700599 output_target_files_dir=output_target_files_temp_dir)
600
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800601 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700602 framework_target_files_temp_dir=framework_target_files_temp_dir,
603 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800604 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700605 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800606
Daniel Normana61cde02019-05-03 14:19:13 -0700607 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700608 framework_target_files_dir=framework_target_files_temp_dir,
609 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700610 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700611
Chris Grossfabf50a2019-05-02 12:42:09 -0700612 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700613 framework_target_files_dir=framework_target_files_temp_dir,
614 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700615 output_target_files_dir=output_target_files_temp_dir,
616 file_name='apkcerts.txt')
617
618 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700619 framework_target_files_dir=framework_target_files_temp_dir,
620 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700621 output_target_files_dir=output_target_files_temp_dir,
622 file_name='apexkeys.txt')
623
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800624
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900625def files_from_path(target_path, extra_args=None):
Tao Bao2ad4b822019-06-27 16:52:12 -0700626 """Gets files under given path.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800627
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900628 Get (sub)files from given target path and return sorted list.
629
630 Args:
631 target_path: Target path to get subfiles.
632 extra_args: List of extra argument for find command. Optional.
633
634 Returns:
635 Sorted files and directories list.
636 """
637
638 find_command = ['find', target_path] + (extra_args or [])
639 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700640 return common.RunAndCheckOutput(['sort'],
641 stdin=find_process.stdout,
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900642 verbose=False)
643
644
645def create_merged_package(temp_dir, framework_target_files, framework_item_list,
646 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700647 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700648 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800649
650 Args:
651 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700652 input target files packages, and also a scratch directory that we use for
653 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700654 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700655 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700656 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700657 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700658 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700659 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700660 vendor_target_files: The name of the zip archive containing the vendor
661 partial target files package.
662 vendor_item_list: The list of items to extract from the partial vendor
663 target files package as is, meaning these items will land in the output
664 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700665 target files package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900666 framework_misc_info_keys: The list of keys to obtain from the framework
667 instance of META/misc_info.txt. The remaining keys from the vendor
668 instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700669 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700670 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800671
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900672 Returns:
673 Path to merged package under temp directory.
674 """
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800675
Daniel Normand5d70ea2019-06-05 15:13:43 -0700676 # Create directory names that we'll use when we extract files from framework,
677 # and vendor, and for zipping the final output.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800678
Daniel Normand5d70ea2019-06-05 15:13:43 -0700679 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
680 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800681 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
682
Daniel Normand5d70ea2019-06-05 15:13:43 -0700683 # Extract "as is" items from the input framework partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800684 # We extract them directly into the output temporary directory since the
685 # items do not need special case processing.
686
Bill Peckham889b0c62019-02-21 18:53:37 -0800687 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700688 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800689 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700690 extract_item_list=framework_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800691
Daniel Normand5d70ea2019-06-05 15:13:43 -0700692 # Extract "as is" items from the input vendor partial target files package. We
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800693 # extract them directly into the output temporary directory since the items
694 # do not need special case processing.
695
Bill Peckham889b0c62019-02-21 18:53:37 -0800696 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700697 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800698 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700699 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800700
Daniel Normand5d70ea2019-06-05 15:13:43 -0700701 # Extract "special" items from the input framework partial target files
702 # package. We extract these items to different directory since they require
703 # special processing before they will end up in the output directory.
704
705 extract_items(
706 target_files=framework_target_files,
707 target_files_temp_dir=framework_target_files_temp_dir,
708 extract_item_list=FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST)
709
710 # Extract "special" items from the input vendor partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800711 # We extract these items to different directory since they require special
712 # processing before they will end up in the output directory.
713
Bill Peckham889b0c62019-02-21 18:53:37 -0800714 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700715 target_files=vendor_target_files,
716 target_files_temp_dir=vendor_target_files_temp_dir,
717 extract_item_list=VENDOR_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800718
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800719 # Now that the temporary directories contain all the extracted files, perform
720 # special case processing on any items that need it. After this function
721 # completes successfully, all the files we need to create the output target
722 # files package are in place.
723
Bill Peckham889b0c62019-02-21 18:53:37 -0800724 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700725 framework_target_files_temp_dir=framework_target_files_temp_dir,
726 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800727 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckhame868aec2019-09-17 17:06:47 -0700728 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800729
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900730 return output_target_files_temp_dir
731
732
733def generate_images(target_files_dir, rebuild_recovery):
734 """Generate images from target files.
735
736 This function takes merged output temporary directory and create images
737 from it.
738
739 Args:
740 target_files_dir: Path to merged temp directory.
741 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
742 devices and write it to the system image.
743 """
744
745 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800746
Daniel Normana4911da2019-03-15 14:36:21 -0700747 add_img_args = ['--verbose']
Paul Trautrimbc3600c2019-08-13 18:07:03 +0900748 add_img_args.append('--add_missing')
Bill Peckhame868aec2019-09-17 17:06:47 -0700749 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700750 if rebuild_recovery:
751 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900752 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800753
754 add_img_to_target_files.main(add_img_args)
755
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900756
757def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700758 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900759
760 Args:
761 target_dir: Path to the target file package which contains misc_info.txt for
762 detailed information for super image.
763 output_super_empty: If provided, copies a super_empty.img file from the
764 target files package to this path.
765 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700766 # Create super_empty.img using the merged misc_info.txt.
767
Daniel Norman4cc9df62019-07-18 10:11:07 -0700768 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700769
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900770 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
771 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700772
773 if use_dynamic_partitions != 'true' and output_super_empty:
774 raise ValueError(
775 'Building super_empty.img requires use_dynamic_partitions=true.')
776 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700777 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700778 build_super_image_args = [
779 misc_info_txt,
780 super_empty_img,
781 ]
782 build_super_image.main(build_super_image_args)
783
784 # Copy super_empty.img to the user-provided output_super_empty location.
785 if output_super_empty:
786 shutil.copyfile(super_empty_img, output_super_empty)
787
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700788
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900789def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700790 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900791
792 Args:
793 output_file: The name of the zip archive target files package.
794 source_dir: The target directory contains package to be archived.
795 temp_dir: Path to temporary directory for any intermediate files.
796 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800797 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900798 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700799 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800800
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900801 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700802 other_content = files_from_path(
803 source_dir,
804 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800805
Tao Bao2ad4b822019-06-27 16:52:12 -0700806 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800807 f.write(meta_content)
808 f.write(other_content)
809
810 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800811 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800812 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700813 '-o',
814 output_zip,
815 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900816 source_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700817 '-l',
818 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800819 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900820
821 logger.info('creating %s', output_file)
Bill Peckham889b0c62019-02-21 18:53:37 -0800822 common.RunAndWait(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900823 logger.info('finished creating %s', output_file)
824
825 return output_zip
826
827
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900828def merge_target_files(temp_dir, framework_target_files, framework_item_list,
829 framework_misc_info_keys, vendor_target_files,
830 vendor_item_list, output_target_files, output_dir,
831 output_item_list, output_ota, output_img,
832 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700833 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900834
835 This function takes framework and vendor target files packages as input,
836 performs various file extractions, special case processing, and finally
837 creates a merged zip archive as output.
838
839 Args:
840 temp_dir: The name of a directory we use when we extract items from the
841 input target files packages, and also a scratch directory that we use for
842 temporary files.
843 framework_target_files: The name of the zip archive containing the framework
844 partial target files package.
845 framework_item_list: The list of items to extract from the partial framework
846 target files package as is, meaning these items will land in the output
847 target files package exactly as they appear in the input partial framework
848 target files package.
849 framework_misc_info_keys: The list of keys to obtain from the framework
850 instance of META/misc_info.txt. The remaining keys from the vendor
851 instance.
852 vendor_target_files: The name of the zip archive containing the vendor
853 partial target files package.
854 vendor_item_list: The list of items to extract from the partial vendor
855 target files package as is, meaning these items will land in the output
856 target files package exactly as they appear in the input partial vendor
857 target files package.
858 output_target_files: The name of the output zip archive target files package
859 created by merging framework and vendor.
860 output_dir: The destination directory for saving merged files.
861 output_item_list: The list of items to copy into the output_dir.
862 output_ota: The name of the output zip archive ota package.
863 output_img: The name of the output zip archive img package.
864 output_super_empty: If provided, creates a super_empty.img file from the
865 merged target files package and saves it at this path.
866 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
867 devices and write it to the system image.
868 """
869
870 logger.info('starting: merge framework %s and vendor %s into output %s',
871 framework_target_files, vendor_target_files, output_target_files)
872
873 output_target_files_temp_dir = create_merged_package(
874 temp_dir, framework_target_files, framework_item_list,
875 vendor_target_files, vendor_item_list, framework_misc_info_keys,
876 rebuild_recovery)
877
Yifan Hongade0d3f2019-08-21 16:37:11 -0700878 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
879 raise RuntimeError("Incompatible VINTF metadata")
880
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900881 generate_images(output_target_files_temp_dir, rebuild_recovery)
882
883 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
884
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900885 # Finally, create the output target files zip archive and/or copy the
886 # output items to the output target files directory.
887
888 if output_dir:
889 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
890
891 if not output_target_files:
892 return
893
894 output_zip = create_target_files_archive(output_target_files,
895 output_target_files_temp_dir,
896 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800897
Daniel Norman74eb74b2019-09-18 14:01:48 -0700898 # Create the IMG package from the merged target files package.
899
900 if output_img:
901 img_from_target_files.main([output_zip, output_img])
902
Daniel Norman3b64ce12019-04-16 16:11:35 -0700903 # Create the OTA package from the merged target files package.
904
905 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -0700906 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -0700907
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700908
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800909def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -0700910 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800911
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800912 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800913 directory. It also cleans up the temporary directory.
914
915 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700916 func: The function to call. Should accept one parameter, the path to the
917 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800918 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800919 """
920
921 # Create a temporary directory. This will serve as the parent of directories
922 # we use when we extract items from the input target files packages, and also
923 # a scratch directory that we use for temporary files.
924
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800925 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
926
927 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800928 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800929 finally:
930 if keep_tmp:
931 logger.info('keeping %s', temp_dir)
932 else:
933 common.Cleanup()
934
935
936def main():
937 """The main function.
938
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800939 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800940 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800941 """
942
943 common.InitLogging()
944
Bill Peckhamf753e152019-02-19 18:02:46 -0800945 def option_handler(o, a):
946 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700947 logger.warning(
948 '--system-target-files has been renamed to --framework-target-files')
949 OPTIONS.framework_target_files = a
950 elif o == '--framework-target-files':
951 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800952 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700953 logger.warning(
954 '--system-item-list has been renamed to --framework-item-list')
955 OPTIONS.framework_item_list = a
956 elif o == '--framework-item-list':
957 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800958 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700959 logger.warning('--system-misc-info-keys has been renamed to '
960 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700961 OPTIONS.framework_misc_info_keys = a
962 elif o == '--framework-misc-info-keys':
963 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800964 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700965 logger.warning(
966 '--other-target-files has been renamed to --vendor-target-files')
967 OPTIONS.vendor_target_files = a
968 elif o == '--vendor-target-files':
969 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800970 elif o == '--other-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700971 logger.warning('--other-item-list has been renamed to --vendor-item-list')
972 OPTIONS.vendor_item_list = a
973 elif o == '--vendor-item-list':
974 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800975 elif o == '--output-target-files':
976 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700977 elif o == '--output-dir':
978 OPTIONS.output_dir = a
979 elif o == '--output-item-list':
980 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700981 elif o == '--output-ota':
982 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700983 elif o == '--output-img':
984 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -0700985 elif o == '--output-super-empty':
986 OPTIONS.output_super_empty = a
Bill Peckhame868aec2019-09-17 17:06:47 -0700987 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -0700988 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700989 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800990 OPTIONS.keep_tmp = True
991 else:
992 return False
993 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800994
Bill Peckhamf753e152019-02-19 18:02:46 -0800995 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -0700996 sys.argv[1:],
997 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -0800998 extra_long_opts=[
999 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001000 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001001 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001002 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001003 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001004 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001005 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001006 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001007 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001008 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001009 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001010 'output-dir=',
1011 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001012 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001013 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001014 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001015 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001016 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001017 ],
1018 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001019
Tao Bao2ad4b822019-06-27 16:52:12 -07001020 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001021 if (args or OPTIONS.framework_target_files is None or
1022 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001023 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
1024 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001025 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001026 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001027
Tao Baoabb806b2019-08-06 10:32:32 -07001028 # Always turn on verbose logging.
1029 OPTIONS.verbose = True
1030
Daniel Normand5d70ea2019-06-05 15:13:43 -07001031 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001032 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001033 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001034 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001035
Daniel Normand5d70ea2019-06-05 15:13:43 -07001036 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001037 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001038 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001039 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001040 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001041
Daniel Normand5d70ea2019-06-05 15:13:43 -07001042 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001043 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001044 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001045 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001046
Daniel Normanfdb38812019-04-15 09:47:24 -07001047 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001048 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001049 else:
1050 output_item_list = None
1051
Daniel Normane5964522019-03-19 10:32:03 -07001052 if not validate_config_lists(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001053 framework_item_list=framework_item_list,
1054 framework_misc_info_keys=framework_misc_info_keys,
1055 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001056 sys.exit(1)
1057
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001058 call_func_with_temp_dir(
1059 lambda temp_dir: merge_target_files(
1060 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001061 framework_target_files=OPTIONS.framework_target_files,
1062 framework_item_list=framework_item_list,
1063 framework_misc_info_keys=framework_misc_info_keys,
1064 vendor_target_files=OPTIONS.vendor_target_files,
1065 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001066 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001067 output_dir=OPTIONS.output_dir,
1068 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001069 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001070 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001071 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001072 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001073
1074
1075if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001076 main()