blob: eb68bc30e67ce13b119d3b373334aa348a8681a8 [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 Norman55417142019-11-25 16:04:36 -0800419 framework_dict=framework_dict, vendor_dict=merged_dict)
Daniel Normand5d70ea2019-06-05 15:13:43 -0700420 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700421 # Ensure that add_img_to_target_files rebuilds super split images for
422 # devices that retrofit dynamic partitions. This flag may have been set to
423 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700424 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700425
Daniel Normand5d70ea2019-06-05 15:13:43 -0700426 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700427 # depending on which dictionary the key came from.
428 # Only the file basename is required because all selinux_fc properties are
429 # replaced with the full path to the file under META/ when misc_info.txt is
430 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700431 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700432 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700433 merged_dict[key] = 'vendor_file_contexts.bin'
434 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700435 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700436 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700437
Daniel Normane5b134a2019-04-17 14:54:06 -0700438 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
439 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700440 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800441
442
Daniel Normand5d70ea2019-06-05 15:13:43 -0700443def process_dynamic_partitions_info_txt(framework_target_files_dir,
444 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700445 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700446 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700447
448 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700449 files from the framework directory and the vendor directory, placing the
450 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700451
Daniel Normand5d70ea2019-06-05 15:13:43 -0700452 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700453 directory does not exist.
454
455 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700456 framework_target_files_dir: The name of a directory containing the special
457 items extracted from the framework target files package.
458 vendor_target_files_dir: The name of a directory containing the special
459 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700460 output_target_files_dir: The name of a directory that will be used to create
461 the output target files package after all the special cases are processed.
462 """
463
464 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700465 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700466 'dynamic_partitions_info.txt')):
467 return
468
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900469 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700470
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900471 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
472 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
473 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
474 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700475
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700476 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700477 framework_dict=framework_dynamic_partitions_dict,
Daniel Norman55417142019-11-25 16:04:36 -0800478 vendor_dict=vendor_dynamic_partitions_dict)
Daniel Normana61cde02019-05-03 14:19:13 -0700479
480 output_dynamic_partitions_info_txt = os.path.join(
481 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700482 write_sorted_data(
483 data=merged_dynamic_partitions_dict,
484 path=output_dynamic_partitions_info_txt)
485
486
Daniel Normand5d70ea2019-06-05 15:13:43 -0700487def process_apex_keys_apk_certs_common(framework_target_files_dir,
488 vendor_target_files_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700489 output_target_files_dir, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700490 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700491
492 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700493 META/apkcerts.txt files from the framework directory and the vendor directory,
494 placing the merged result in the output directory. The precondition in that
495 the files are already extracted. The post condition is that the output
496 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700497
498 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700499 framework_target_files_dir: The name of a directory containing the special
500 items extracted from the framework target files package.
501 vendor_target_files_dir: The name of a directory containing the special
502 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700503 output_target_files_dir: The name of a directory that will be used to create
504 the output target files package after all the special cases are processed.
505 file_name: The name of the file to merge. One of apkcerts.txt or
506 apexkeys.txt.
507 """
508
509 def read_helper(d):
510 temp = {}
511 file_path = os.path.join(d, 'META', file_name)
512 with open(file_path) as f:
513 for line in f:
514 if line.strip():
515 temp[line.split()[0]] = line.strip()
516 return temp
517
Daniel Normand5d70ea2019-06-05 15:13:43 -0700518 framework_dict = read_helper(framework_target_files_dir)
519 vendor_dict = read_helper(vendor_target_files_dir)
Chris Grossfabf50a2019-05-02 12:42:09 -0700520
Daniel Normand5d70ea2019-06-05 15:13:43 -0700521 for key in framework_dict:
522 if key in vendor_dict and vendor_dict[key] != framework_dict[key]:
Chris Grossfabf50a2019-05-02 12:42:09 -0700523 raise ValueError('Conflicting entries found in %s:\n %s and\n %s' %
Daniel Normand5d70ea2019-06-05 15:13:43 -0700524 (file_name, framework_dict[key], vendor_dict[key]))
525 vendor_dict[key] = framework_dict[key]
Chris Grossfabf50a2019-05-02 12:42:09 -0700526
527 output_file = os.path.join(output_target_files_dir, 'META', file_name)
528
Daniel Normand5d70ea2019-06-05 15:13:43 -0700529 write_sorted_data(data=vendor_dict.values(), path=output_file)
Daniel Normana61cde02019-05-03 14:19:13 -0700530
531
Daniel Normand5d70ea2019-06-05 15:13:43 -0700532def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700533 output_target_files_dir):
534 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700535 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
536 'framework_file_contexts.bin')
537 if not os.path.exists(framework_fc_path):
538 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
539 'file_contexts.bin')
540 if not os.path.exists(framework_fc_path):
541 raise ValueError('Missing framework file_contexts.bin.')
542 shutil.copyfile(
543 framework_fc_path,
544 os.path.join(output_target_files_dir, 'META',
545 'framework_file_contexts.bin'))
546
547 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
548 'vendor_file_contexts.bin')
549 if not os.path.exists(vendor_fc_path):
550 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700551 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700552 if not os.path.exists(vendor_fc_path):
553 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700554 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700555 vendor_fc_path,
556 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700557
558
Daniel Normand5d70ea2019-06-05 15:13:43 -0700559def process_special_cases(framework_target_files_temp_dir,
560 vendor_target_files_temp_dir,
561 output_target_files_temp_dir,
Bill Peckhame868aec2019-09-17 17:06:47 -0700562 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700563 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800564
565 Certain files in the output target files package require special-case
566 processing. This function performs all that special-case processing.
567
568 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700569 framework_target_files_temp_dir: The name of a directory containing the
570 special items extracted from the framework target files package.
571 vendor_target_files_temp_dir: The name of a directory containing the special
572 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700573 output_target_files_temp_dir: The name of a directory that will be used to
574 create the output target files package after all the special cases are
575 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700576 framework_misc_info_keys: A list of keys to obtain from the framework
577 instance of META/misc_info.txt. The remaining keys from the vendor
578 instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800579 """
580
Daniel Normand5d70ea2019-06-05 15:13:43 -0700581 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700582 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700583 framework_target_files_temp_dir=framework_target_files_temp_dir,
584 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700585 output_target_files_temp_dir=output_target_files_temp_dir)
586
Daniel Norman72c626f2019-05-13 15:58:14 -0700587 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700588 framework_target_files_dir=framework_target_files_temp_dir,
589 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700590 output_target_files_dir=output_target_files_temp_dir)
591
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800592 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700593 framework_target_files_temp_dir=framework_target_files_temp_dir,
594 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800595 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700596 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800597
Daniel Normana61cde02019-05-03 14:19:13 -0700598 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700599 framework_target_files_dir=framework_target_files_temp_dir,
600 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700601 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700602
Chris Grossfabf50a2019-05-02 12:42:09 -0700603 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700604 framework_target_files_dir=framework_target_files_temp_dir,
605 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700606 output_target_files_dir=output_target_files_temp_dir,
607 file_name='apkcerts.txt')
608
609 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700610 framework_target_files_dir=framework_target_files_temp_dir,
611 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700612 output_target_files_dir=output_target_files_temp_dir,
613 file_name='apexkeys.txt')
614
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800615
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900616def files_from_path(target_path, extra_args=None):
Tao Bao2ad4b822019-06-27 16:52:12 -0700617 """Gets files under given path.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800618
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900619 Get (sub)files from given target path and return sorted list.
620
621 Args:
622 target_path: Target path to get subfiles.
623 extra_args: List of extra argument for find command. Optional.
624
625 Returns:
626 Sorted files and directories list.
627 """
628
629 find_command = ['find', target_path] + (extra_args or [])
630 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700631 return common.RunAndCheckOutput(['sort'],
632 stdin=find_process.stdout,
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900633 verbose=False)
634
635
636def create_merged_package(temp_dir, framework_target_files, framework_item_list,
637 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700638 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700639 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800640
641 Args:
642 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700643 input target files packages, and also a scratch directory that we use for
644 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700645 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700646 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700647 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700648 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700649 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700650 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700651 vendor_target_files: The name of the zip archive containing the vendor
652 partial target files package.
653 vendor_item_list: The list of items to extract from the partial vendor
654 target files package as is, meaning these items will land in the output
655 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700656 target files package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900657 framework_misc_info_keys: The list of keys to obtain from the framework
658 instance of META/misc_info.txt. The remaining keys from the vendor
659 instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700660 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700661 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800662
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900663 Returns:
664 Path to merged package under temp directory.
665 """
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800666
Daniel Normand5d70ea2019-06-05 15:13:43 -0700667 # Create directory names that we'll use when we extract files from framework,
668 # and vendor, and for zipping the final output.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800669
Daniel Normand5d70ea2019-06-05 15:13:43 -0700670 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
671 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800672 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
673
Daniel Normand5d70ea2019-06-05 15:13:43 -0700674 # Extract "as is" items from the input framework partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800675 # We extract them directly into the output temporary directory since the
676 # items do not need special case processing.
677
Bill Peckham889b0c62019-02-21 18:53:37 -0800678 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700679 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800680 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700681 extract_item_list=framework_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800682
Daniel Normand5d70ea2019-06-05 15:13:43 -0700683 # Extract "as is" items from the input vendor partial target files package. We
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800684 # extract them directly into the output temporary directory since the items
685 # 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=vendor_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=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800691
Daniel Normand5d70ea2019-06-05 15:13:43 -0700692 # Extract "special" items from the input framework partial target files
693 # package. We extract these items to different directory since they require
694 # special processing before they will end up in the output directory.
695
696 extract_items(
697 target_files=framework_target_files,
698 target_files_temp_dir=framework_target_files_temp_dir,
699 extract_item_list=FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST)
700
701 # Extract "special" items from the input vendor partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800702 # We extract these items to different directory since they require special
703 # processing before they will end up in the output directory.
704
Bill Peckham889b0c62019-02-21 18:53:37 -0800705 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700706 target_files=vendor_target_files,
707 target_files_temp_dir=vendor_target_files_temp_dir,
708 extract_item_list=VENDOR_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800709
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800710 # Now that the temporary directories contain all the extracted files, perform
711 # special case processing on any items that need it. After this function
712 # completes successfully, all the files we need to create the output target
713 # files package are in place.
714
Bill Peckham889b0c62019-02-21 18:53:37 -0800715 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700716 framework_target_files_temp_dir=framework_target_files_temp_dir,
717 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800718 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckhame868aec2019-09-17 17:06:47 -0700719 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800720
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900721 return output_target_files_temp_dir
722
723
724def generate_images(target_files_dir, rebuild_recovery):
725 """Generate images from target files.
726
727 This function takes merged output temporary directory and create images
728 from it.
729
730 Args:
731 target_files_dir: Path to merged temp directory.
732 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
733 devices and write it to the system image.
734 """
735
736 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800737
Daniel Normana4911da2019-03-15 14:36:21 -0700738 add_img_args = ['--verbose']
Paul Trautrimbc3600c2019-08-13 18:07:03 +0900739 add_img_args.append('--add_missing')
Bill Peckhame868aec2019-09-17 17:06:47 -0700740 # TODO(b/132730255): Remove this if statement.
Daniel Normana4911da2019-03-15 14:36:21 -0700741 if rebuild_recovery:
742 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900743 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800744
745 add_img_to_target_files.main(add_img_args)
746
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900747
748def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700749 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900750
751 Args:
752 target_dir: Path to the target file package which contains misc_info.txt for
753 detailed information for super image.
754 output_super_empty: If provided, copies a super_empty.img file from the
755 target files package to this path.
756 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700757 # Create super_empty.img using the merged misc_info.txt.
758
Daniel Norman4cc9df62019-07-18 10:11:07 -0700759 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700760
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900761 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
762 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700763
764 if use_dynamic_partitions != 'true' and output_super_empty:
765 raise ValueError(
766 'Building super_empty.img requires use_dynamic_partitions=true.')
767 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700768 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700769 build_super_image_args = [
770 misc_info_txt,
771 super_empty_img,
772 ]
773 build_super_image.main(build_super_image_args)
774
775 # Copy super_empty.img to the user-provided output_super_empty location.
776 if output_super_empty:
777 shutil.copyfile(super_empty_img, output_super_empty)
778
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700779
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900780def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700781 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900782
783 Args:
784 output_file: The name of the zip archive target files package.
785 source_dir: The target directory contains package to be archived.
786 temp_dir: Path to temporary directory for any intermediate files.
787 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800788 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900789 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700790 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800791
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900792 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700793 other_content = files_from_path(
794 source_dir,
795 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800796
Tao Bao2ad4b822019-06-27 16:52:12 -0700797 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800798 f.write(meta_content)
799 f.write(other_content)
800
801 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800802 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800803 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700804 '-o',
805 output_zip,
806 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900807 source_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700808 '-l',
809 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800810 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900811
812 logger.info('creating %s', output_file)
Bill Peckham889b0c62019-02-21 18:53:37 -0800813 common.RunAndWait(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900814 logger.info('finished creating %s', output_file)
815
816 return output_zip
817
818
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900819def merge_target_files(temp_dir, framework_target_files, framework_item_list,
820 framework_misc_info_keys, vendor_target_files,
821 vendor_item_list, output_target_files, output_dir,
822 output_item_list, output_ota, output_img,
823 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700824 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900825
826 This function takes framework and vendor target files packages as input,
827 performs various file extractions, special case processing, and finally
828 creates a merged zip archive as output.
829
830 Args:
831 temp_dir: The name of a directory we use when we extract items from the
832 input target files packages, and also a scratch directory that we use for
833 temporary files.
834 framework_target_files: The name of the zip archive containing the framework
835 partial target files package.
836 framework_item_list: The list of items to extract from the partial framework
837 target files package as is, meaning these items will land in the output
838 target files package exactly as they appear in the input partial framework
839 target files package.
840 framework_misc_info_keys: The list of keys to obtain from the framework
841 instance of META/misc_info.txt. The remaining keys from the vendor
842 instance.
843 vendor_target_files: The name of the zip archive containing the vendor
844 partial target files package.
845 vendor_item_list: The list of items to extract from the partial vendor
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 vendor
848 target files package.
849 output_target_files: The name of the output zip archive target files package
850 created by merging framework and vendor.
851 output_dir: The destination directory for saving merged files.
852 output_item_list: The list of items to copy into the output_dir.
853 output_ota: The name of the output zip archive ota package.
854 output_img: The name of the output zip archive img package.
855 output_super_empty: If provided, creates a super_empty.img file from the
856 merged target files package and saves it at this path.
857 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
858 devices and write it to the system image.
859 """
860
861 logger.info('starting: merge framework %s and vendor %s into output %s',
862 framework_target_files, vendor_target_files, output_target_files)
863
864 output_target_files_temp_dir = create_merged_package(
865 temp_dir, framework_target_files, framework_item_list,
866 vendor_target_files, vendor_item_list, framework_misc_info_keys,
867 rebuild_recovery)
868
Yifan Hongade0d3f2019-08-21 16:37:11 -0700869 if not check_target_files_vintf.CheckVintf(output_target_files_temp_dir):
870 raise RuntimeError("Incompatible VINTF metadata")
871
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900872 generate_images(output_target_files_temp_dir, rebuild_recovery)
873
874 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
875
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900876 # Finally, create the output target files zip archive and/or copy the
877 # output items to the output target files directory.
878
879 if output_dir:
880 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
881
882 if not output_target_files:
883 return
884
885 output_zip = create_target_files_archive(output_target_files,
886 output_target_files_temp_dir,
887 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800888
Daniel Norman74eb74b2019-09-18 14:01:48 -0700889 # Create the IMG package from the merged target files package.
890
891 if output_img:
892 img_from_target_files.main([output_zip, output_img])
893
Daniel Norman3b64ce12019-04-16 16:11:35 -0700894 # Create the OTA package from the merged target files package.
895
896 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -0700897 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -0700898
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700899
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800900def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -0700901 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800902
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800903 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800904 directory. It also cleans up the temporary directory.
905
906 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700907 func: The function to call. Should accept one parameter, the path to the
908 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800909 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800910 """
911
912 # Create a temporary directory. This will serve as the parent of directories
913 # we use when we extract items from the input target files packages, and also
914 # a scratch directory that we use for temporary files.
915
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800916 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
917
918 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800919 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800920 finally:
921 if keep_tmp:
922 logger.info('keeping %s', temp_dir)
923 else:
924 common.Cleanup()
925
926
927def main():
928 """The main function.
929
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800930 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800931 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800932 """
933
934 common.InitLogging()
935
Bill Peckhamf753e152019-02-19 18:02:46 -0800936 def option_handler(o, a):
937 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700938 logger.warning(
939 '--system-target-files has been renamed to --framework-target-files')
940 OPTIONS.framework_target_files = a
941 elif o == '--framework-target-files':
942 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800943 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700944 logger.warning(
945 '--system-item-list has been renamed to --framework-item-list')
946 OPTIONS.framework_item_list = a
947 elif o == '--framework-item-list':
948 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800949 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700950 logger.warning('--system-misc-info-keys has been renamed to '
951 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700952 OPTIONS.framework_misc_info_keys = a
953 elif o == '--framework-misc-info-keys':
954 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800955 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700956 logger.warning(
957 '--other-target-files has been renamed to --vendor-target-files')
958 OPTIONS.vendor_target_files = a
959 elif o == '--vendor-target-files':
960 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800961 elif o == '--other-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700962 logger.warning('--other-item-list has been renamed to --vendor-item-list')
963 OPTIONS.vendor_item_list = a
964 elif o == '--vendor-item-list':
965 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800966 elif o == '--output-target-files':
967 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700968 elif o == '--output-dir':
969 OPTIONS.output_dir = a
970 elif o == '--output-item-list':
971 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700972 elif o == '--output-ota':
973 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700974 elif o == '--output-img':
975 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -0700976 elif o == '--output-super-empty':
977 OPTIONS.output_super_empty = a
Bill Peckhame868aec2019-09-17 17:06:47 -0700978 elif o == '--rebuild_recovery': # TODO(b/132730255): Warn
Daniel Normana4911da2019-03-15 14:36:21 -0700979 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700980 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800981 OPTIONS.keep_tmp = True
982 else:
983 return False
984 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800985
Bill Peckhamf753e152019-02-19 18:02:46 -0800986 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -0700987 sys.argv[1:],
988 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -0800989 extra_long_opts=[
990 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -0700991 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800992 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -0700993 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800994 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -0700995 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800996 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -0700997 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800998 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -0700999 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001000 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001001 'output-dir=',
1002 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001003 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001004 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001005 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001006 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001007 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001008 ],
1009 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001010
Tao Bao2ad4b822019-06-27 16:52:12 -07001011 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001012 if (args or OPTIONS.framework_target_files is None or
1013 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001014 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
1015 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001016 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001017 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001018
Tao Baoabb806b2019-08-06 10:32:32 -07001019 # Always turn on verbose logging.
1020 OPTIONS.verbose = True
1021
Daniel Normand5d70ea2019-06-05 15:13:43 -07001022 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001023 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001024 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001025 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001026
Daniel Normand5d70ea2019-06-05 15:13:43 -07001027 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001028 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001029 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001030 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001031 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001032
Daniel Normand5d70ea2019-06-05 15:13:43 -07001033 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001034 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001035 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001036 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001037
Daniel Normanfdb38812019-04-15 09:47:24 -07001038 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001039 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001040 else:
1041 output_item_list = None
1042
Daniel Normane5964522019-03-19 10:32:03 -07001043 if not validate_config_lists(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001044 framework_item_list=framework_item_list,
1045 framework_misc_info_keys=framework_misc_info_keys,
1046 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001047 sys.exit(1)
1048
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001049 call_func_with_temp_dir(
1050 lambda temp_dir: merge_target_files(
1051 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001052 framework_target_files=OPTIONS.framework_target_files,
1053 framework_item_list=framework_item_list,
1054 framework_misc_info_keys=framework_misc_info_keys,
1055 vendor_target_files=OPTIONS.vendor_target_files,
1056 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001057 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001058 output_dir=OPTIONS.output_dir,
1059 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001060 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001061 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001062 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001063 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001064
1065
1066if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001067 main()