blob: cfffbc73521654bd03c4e036731a148968e208f3 [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
71 Rebuild the recovery patch used by non-A/B devices and write it to the
72 system image.
Bill Peckham364c1cc2019-03-29 18:27:23 -070073
74 --keep-tmp
75 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080076"""
77
78from __future__ import print_function
79
Bill Peckhame9eb5f92019-02-01 15:52:10 -080080import fnmatch
81import logging
82import os
Daniel Normanfdb38812019-04-15 09:47:24 -070083import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -070084import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -080085import sys
86import zipfile
87
Bill Peckhame9eb5f92019-02-01 15:52:10 -080088import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070089import build_super_image
90import 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
Daniel Normana4911da2019-03-15 14:36:21 -0700108OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800109OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800110
Daniel Normand5d70ea2019-06-05 15:13:43 -0700111# DEFAULT_FRAMEWORK_ITEM_LIST is a list of items to extract from the partial
112# framework target files package as is, meaning these items will land in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800113# output target files package exactly as they appear in the input partial
Daniel Normand5d70ea2019-06-05 15:13:43 -0700114# framework target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800115
Daniel Normand5d70ea2019-06-05 15:13:43 -0700116DEFAULT_FRAMEWORK_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800117 'META/apkcerts.txt',
118 'META/filesystem_config.txt',
119 'META/root_filesystem_config.txt',
120 'META/system_manifest.xml',
121 'META/system_matrix.xml',
122 'META/update_engine_config.txt',
123 'PRODUCT/*',
124 'ROOT/*',
125 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700126)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800127
Daniel Normand5d70ea2019-06-05 15:13:43 -0700128# FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
129# partial framework target files package that need some special processing, such
130# as some sort of combination with items from the partial vendor target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800131# package.
132
Daniel Normand5d70ea2019-06-05 15:13:43 -0700133FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800134
Daniel Normand5d70ea2019-06-05 15:13:43 -0700135# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
136# framework instance of META/misc_info.txt. The remaining keys from the
137# vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800138
Daniel Normand5d70ea2019-06-05 15:13:43 -0700139DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800140 'avb_system_hashtree_enable',
141 'avb_system_add_hashtree_footer_args',
142 'avb_system_key_path',
143 'avb_system_algorithm',
144 'avb_system_rollback_index_location',
145 'avb_product_hashtree_enable',
146 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900147 'avb_system_ext_hashtree_enable',
148 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800149 'system_root_image',
150 'root_dir',
151 'ab_update',
152 'default_system_dev_certificate',
153 'system_size',
Daniel Normanedf12472019-05-22 10:47:08 -0700154)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800155
Daniel Normand5d70ea2019-06-05 15:13:43 -0700156# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
157# vendor target files package as is, meaning these items will land in the output
158# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800159# files package.
160
Daniel Normand5d70ea2019-06-05 15:13:43 -0700161DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800162 'META/boot_filesystem_config.txt',
163 'META/otakeys.txt',
164 'META/releasetools.py',
165 'META/vendor_filesystem_config.txt',
166 'META/vendor_manifest.xml',
167 'META/vendor_matrix.xml',
168 'BOOT/*',
169 'DATA/*',
170 'ODM/*',
171 'OTA/android-info.txt',
172 'PREBUILT_IMAGES/*',
173 'RADIO/*',
174 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700175)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800176
Daniel Normand5d70ea2019-06-05 15:13:43 -0700177# VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
178# partial vendor target files package that need some special processing, such as
179# some sort of combination with items from the partial framework target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800180# package.
181
Daniel Normand5d70ea2019-06-05 15:13:43 -0700182VENDOR_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Daniel Normanedf12472019-05-22 10:47:08 -0700183
184# The merge config lists should not attempt to extract items from both
185# builds for any of the following partitions. The partitions in
186# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700187# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700188
189SINGLE_BUILD_PARTITIONS = (
190 'BOOT/',
191 'DATA/',
192 'ODM/',
193 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900194 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700195 'RADIO/',
196 'RECOVERY/',
197 'ROOT/',
198 'SYSTEM/',
199 'SYSTEM_OTHER/',
200 'VENDOR/',
201)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800202
203
Chris Grossfabf50a2019-05-02 12:42:09 -0700204def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700205 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700206
Tao Bao2ad4b822019-06-27 16:52:12 -0700207 This function sorts the contents of the list or dict and then writes the
208 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700209
210 Args:
211 data: The list or dict to sort and write.
212 path: Path to the file to write the sorted values to. The file at path will
213 be overridden if it exists.
214 """
215 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700216 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700217 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
218 data, dict) else '{}\n'.format(entry)
219 output.write(out_str)
220
221
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800222def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700223 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800224
225 This function extracts from the specified target files zip archive into the
226 specified temporary directory, the items specified in the extract item list.
227
228 Args:
229 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800230 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700231 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800232 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800233 """
234
235 logger.info('extracting from %s', target_files)
236
237 # Filter the extract_item_list to remove any items that do not exist in the
238 # zip file. Otherwise, the extraction step will fail.
239
Daniel Norman4cc9df62019-07-18 10:11:07 -0700240 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800241 target_files_namelist = target_files_zipfile.namelist()
242
243 filtered_extract_item_list = []
244 for pattern in extract_item_list:
245 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
246 if not matching_namelist:
247 logger.warning('no match for %s', pattern)
248 else:
249 filtered_extract_item_list.append(pattern)
250
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800251 # Extract from target_files into target_files_temp_dir the
252 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800253
Daniel Normane5b134a2019-04-17 14:54:06 -0700254 common.UnzipToDir(target_files, target_files_temp_dir,
255 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800256
257
Daniel Normanfdb38812019-04-15 09:47:24 -0700258def copy_items(from_dir, to_dir, patterns):
259 """Similar to extract_items() except uses an input dir instead of zip."""
260 file_paths = []
261 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700262 file_paths.extend(
263 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
264 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700265
266 filtered_file_paths = set()
267 for pattern in patterns:
268 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
269
270 for file_path in filtered_file_paths:
271 original_file_path = os.path.join(from_dir, file_path)
272 copied_file_path = os.path.join(to_dir, file_path)
273 copied_file_dir = os.path.dirname(copied_file_path)
274 if not os.path.exists(copied_file_dir):
275 os.makedirs(copied_file_dir)
276 if os.path.islink(original_file_path):
277 os.symlink(os.readlink(original_file_path), copied_file_path)
278 else:
279 shutil.copyfile(original_file_path, copied_file_path)
280
281
Daniel Normand5d70ea2019-06-05 15:13:43 -0700282def validate_config_lists(framework_item_list, framework_misc_info_keys,
283 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700284 """Performs validations on the merge config lists.
285
286 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700287 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700288 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700289 framework_misc_info_keys: A list of keys to obtain from the framework
290 instance of META/misc_info.txt. The remaining keys from the vendor
291 instance.
292 vendor_item_list: The list of items to extract from the partial vendor
293 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700294
295 Returns:
296 False if a validation fails, otherwise true.
297 """
Daniel Normanedf12472019-05-22 10:47:08 -0700298 has_error = False
299
Daniel Normand5d70ea2019-06-05 15:13:43 -0700300 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
301 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700302
Daniel Normand5d70ea2019-06-05 15:13:43 -0700303 combined_item_set = set(framework_item_list)
304 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700305
306 # Check that the merge config lists are not missing any item specified
307 # by the default config lists.
308 difference = default_combined_item_set.difference(combined_item_set)
309 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700310 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700311 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700312 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700313 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700314 has_error = True
315
316 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700317 in_framework = any(
318 item.startswith(partition) for item in framework_item_list)
319 in_vendor = any(item.startswith(partition) for item in vendor_item_list)
320 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700321 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700322 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900323 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700324 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700325 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700326
Daniel Normand5d70ea2019-06-05 15:13:43 -0700327 if ('dynamic_partition_list' in framework_misc_info_keys) or (
328 'super_partition_groups' in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700329 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700330 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700331 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700332
Daniel Normanedf12472019-05-22 10:47:08 -0700333 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700334
335
Daniel Normand5d70ea2019-06-05 15:13:43 -0700336def process_ab_partitions_txt(framework_target_files_temp_dir,
337 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700338 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700339 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800340
Tao Bao2ad4b822019-06-27 16:52:12 -0700341 This function merges the contents of the META/ab_partitions.txt files from the
342 framework directory and the vendor directory, placing the merged result in the
343 output directory. The precondition in that the files are already extracted.
344 The post condition is that the output META/ab_partitions.txt contains the
345 merged content. The format for each ab_partitions.txt a one partition name per
346 line. The output file contains the union of the parition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800347
348 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700349 framework_target_files_temp_dir: The name of a directory containing the
350 special items extracted from the framework target files package.
351 vendor_target_files_temp_dir: The name of a directory containing the special
352 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700353 output_target_files_temp_dir: The name of a directory that will be used to
354 create the output target files package after all the special cases are
355 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800356 """
357
Daniel Normand5d70ea2019-06-05 15:13:43 -0700358 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
359 'META', 'ab_partitions.txt')
360
361 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700362 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800363
Daniel Normand5d70ea2019-06-05 15:13:43 -0700364 with open(framework_ab_partitions_txt) as f:
365 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800366
Daniel Normand5d70ea2019-06-05 15:13:43 -0700367 with open(vendor_ab_partitions_txt) as f:
368 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800369
Daniel Normand5d70ea2019-06-05 15:13:43 -0700370 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800371
Daniel Normane5b134a2019-04-17 14:54:06 -0700372 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
373 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800374
Chris Grossfabf50a2019-05-02 12:42:09 -0700375 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800376
377
Bill Peckham364c1cc2019-03-29 18:27:23 -0700378def append_recovery_to_filesystem_config(output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700379 """Performs special processing for META/filesystem_config.txt.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700380
Tao Bao2ad4b822019-06-27 16:52:12 -0700381 This function appends recovery information to META/filesystem_config.txt so
382 that recovery patch regeneration will succeed.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700383
384 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700385 output_target_files_temp_dir: The name of a directory that will be used to
386 create the output target files package after all the special cases are
387 processed. We find filesystem_config.txt here.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700388 """
389
Daniel Normane5b134a2019-04-17 14:54:06 -0700390 filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
391 'filesystem_config.txt')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700392
393 with open(filesystem_config_txt, 'a') as f:
394 # TODO(bpeckham) this data is hard coded. It should be generated
395 # programmatically.
Daniel Normane5b134a2019-04-17 14:54:06 -0700396 f.write('system/bin/install-recovery.sh 0 0 750 '
397 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
398 f.write('system/recovery-from-boot.p 0 0 644 '
399 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
400 f.write('system/etc/recovery.img 0 0 440 '
401 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700402
403
Daniel Normand5d70ea2019-06-05 15:13:43 -0700404def process_misc_info_txt(framework_target_files_temp_dir,
405 vendor_target_files_temp_dir,
406 output_target_files_temp_dir,
407 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700408 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800409
410 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700411 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800412 output directory. The precondition in that the files are already extracted.
413 The post condition is that the output META/misc_info.txt contains the merged
414 content.
415
416 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700417 framework_target_files_temp_dir: The name of a directory containing the
418 special items extracted from the framework target files package.
419 vendor_target_files_temp_dir: The name of a directory containing the special
420 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700421 output_target_files_temp_dir: The name of a directory that will be used to
422 create the output target files package after all the special cases are
423 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700424 framework_misc_info_keys: A list of keys to obtain from the framework
425 instance of META/misc_info.txt. The remaining keys from the vendor
426 instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800427 """
428
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900429 misc_info_path = ['META', 'misc_info.txt']
430 framework_dict = common.LoadDictionaryFromFile(
431 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800432
Daniel Normand5d70ea2019-06-05 15:13:43 -0700433 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800434
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900435 merged_dict = common.LoadDictionaryFromFile(
436 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800437
Daniel Normand5d70ea2019-06-05 15:13:43 -0700438 # Replace certain values in merged_dict with values from
439 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800440
Daniel Normand5d70ea2019-06-05 15:13:43 -0700441 for key in framework_misc_info_keys:
442 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800443
Daniel Norman19b9fe92019-03-19 14:48:02 -0700444 # Merge misc info keys used for Dynamic Partitions.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700445 if (merged_dict.get('use_dynamic_partitions') == 'true') and (
446 framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700447 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700448 framework_dict=framework_dict,
449 vendor_dict=merged_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700450 size_prefix='super_',
451 size_suffix='_group_size',
452 list_prefix='super_',
453 list_suffix='_partition_list')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700454 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700455 # Ensure that add_img_to_target_files rebuilds super split images for
456 # devices that retrofit dynamic partitions. This flag may have been set to
457 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700458 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700459
Daniel Normand5d70ea2019-06-05 15:13:43 -0700460 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700461 # depending on which dictionary the key came from.
462 # Only the file basename is required because all selinux_fc properties are
463 # replaced with the full path to the file under META/ when misc_info.txt is
464 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700465 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700466 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700467 merged_dict[key] = 'vendor_file_contexts.bin'
468 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700469 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700470 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700471
Daniel Normane5b134a2019-04-17 14:54:06 -0700472 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
473 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700474 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800475
476
Daniel Normand5d70ea2019-06-05 15:13:43 -0700477def process_dynamic_partitions_info_txt(framework_target_files_dir,
478 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700479 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700480 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700481
482 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700483 files from the framework directory and the vendor directory, placing the
484 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700485
Daniel Normand5d70ea2019-06-05 15:13:43 -0700486 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700487 directory does not exist.
488
489 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700490 framework_target_files_dir: The name of a directory containing the special
491 items extracted from the framework target files package.
492 vendor_target_files_dir: The name of a directory containing the special
493 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700494 output_target_files_dir: The name of a directory that will be used to create
495 the output target files package after all the special cases are processed.
496 """
497
498 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700499 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700500 'dynamic_partitions_info.txt')):
501 return
502
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900503 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700504
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900505 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
506 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
507 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
508 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700509
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700510 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700511 framework_dict=framework_dynamic_partitions_dict,
512 vendor_dict=vendor_dynamic_partitions_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700513 # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
514 include_dynamic_partition_list=False,
515 size_suffix='_size',
516 list_suffix='_partition_list')
517
518 output_dynamic_partitions_info_txt = os.path.join(
519 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700520 write_sorted_data(
521 data=merged_dynamic_partitions_dict,
522 path=output_dynamic_partitions_info_txt)
523
524
Daniel Normand5d70ea2019-06-05 15:13:43 -0700525def process_apex_keys_apk_certs_common(framework_target_files_dir,
526 vendor_target_files_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700527 output_target_files_dir, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700528 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700529
530 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700531 META/apkcerts.txt files from the framework directory and the vendor directory,
532 placing the merged result in the output directory. The precondition in that
533 the files are already extracted. The post condition is that the output
534 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700535
536 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700537 framework_target_files_dir: The name of a directory containing the special
538 items extracted from the framework target files package.
539 vendor_target_files_dir: The name of a directory containing the special
540 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700541 output_target_files_dir: The name of a directory that will be used to create
542 the output target files package after all the special cases are processed.
543 file_name: The name of the file to merge. One of apkcerts.txt or
544 apexkeys.txt.
545 """
546
547 def read_helper(d):
548 temp = {}
549 file_path = os.path.join(d, 'META', file_name)
550 with open(file_path) as f:
551 for line in f:
552 if line.strip():
553 temp[line.split()[0]] = line.strip()
554 return temp
555
Daniel Normand5d70ea2019-06-05 15:13:43 -0700556 framework_dict = read_helper(framework_target_files_dir)
557 vendor_dict = read_helper(vendor_target_files_dir)
Chris Grossfabf50a2019-05-02 12:42:09 -0700558
Daniel Normand5d70ea2019-06-05 15:13:43 -0700559 for key in framework_dict:
560 if key in vendor_dict and vendor_dict[key] != framework_dict[key]:
Chris Grossfabf50a2019-05-02 12:42:09 -0700561 raise ValueError('Conflicting entries found in %s:\n %s and\n %s' %
Daniel Normand5d70ea2019-06-05 15:13:43 -0700562 (file_name, framework_dict[key], vendor_dict[key]))
563 vendor_dict[key] = framework_dict[key]
Chris Grossfabf50a2019-05-02 12:42:09 -0700564
565 output_file = os.path.join(output_target_files_dir, 'META', file_name)
566
Daniel Normand5d70ea2019-06-05 15:13:43 -0700567 write_sorted_data(data=vendor_dict.values(), path=output_file)
Daniel Normana61cde02019-05-03 14:19:13 -0700568
569
Daniel Normand5d70ea2019-06-05 15:13:43 -0700570def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700571 output_target_files_dir):
572 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700573 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
574 'framework_file_contexts.bin')
575 if not os.path.exists(framework_fc_path):
576 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
577 'file_contexts.bin')
578 if not os.path.exists(framework_fc_path):
579 raise ValueError('Missing framework file_contexts.bin.')
580 shutil.copyfile(
581 framework_fc_path,
582 os.path.join(output_target_files_dir, 'META',
583 'framework_file_contexts.bin'))
584
585 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
586 'vendor_file_contexts.bin')
587 if not os.path.exists(vendor_fc_path):
588 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700589 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700590 if not os.path.exists(vendor_fc_path):
591 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700592 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700593 vendor_fc_path,
594 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700595
596
Daniel Normand5d70ea2019-06-05 15:13:43 -0700597def process_special_cases(framework_target_files_temp_dir,
598 vendor_target_files_temp_dir,
599 output_target_files_temp_dir,
600 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700601 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800602
603 Certain files in the output target files package require special-case
604 processing. This function performs all that special-case processing.
605
606 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700607 framework_target_files_temp_dir: The name of a directory containing the
608 special items extracted from the framework target files package.
609 vendor_target_files_temp_dir: The name of a directory containing the special
610 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700611 output_target_files_temp_dir: The name of a directory that will be used to
612 create the output target files package after all the special cases are
613 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700614 framework_misc_info_keys: A list of keys to obtain from the framework
615 instance of META/misc_info.txt. The remaining keys from the vendor
616 instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700617 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700618 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800619 """
620
Daniel Normand5d70ea2019-06-05 15:13:43 -0700621 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700622 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700623 framework_target_files_temp_dir=framework_target_files_temp_dir,
624 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700625 output_target_files_temp_dir=output_target_files_temp_dir)
626
627 if rebuild_recovery:
628 append_recovery_to_filesystem_config(
629 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800630
Daniel Norman72c626f2019-05-13 15:58:14 -0700631 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700632 framework_target_files_dir=framework_target_files_temp_dir,
633 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700634 output_target_files_dir=output_target_files_temp_dir)
635
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800636 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700637 framework_target_files_temp_dir=framework_target_files_temp_dir,
638 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800639 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700640 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800641
Daniel Normana61cde02019-05-03 14:19:13 -0700642 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700643 framework_target_files_dir=framework_target_files_temp_dir,
644 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700645 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700646
Chris Grossfabf50a2019-05-02 12:42:09 -0700647 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700648 framework_target_files_dir=framework_target_files_temp_dir,
649 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700650 output_target_files_dir=output_target_files_temp_dir,
651 file_name='apkcerts.txt')
652
653 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700654 framework_target_files_dir=framework_target_files_temp_dir,
655 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700656 output_target_files_dir=output_target_files_temp_dir,
657 file_name='apexkeys.txt')
658
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800659
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900660def files_from_path(target_path, extra_args=None):
Tao Bao2ad4b822019-06-27 16:52:12 -0700661 """Gets files under given path.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800662
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900663 Get (sub)files from given target path and return sorted list.
664
665 Args:
666 target_path: Target path to get subfiles.
667 extra_args: List of extra argument for find command. Optional.
668
669 Returns:
670 Sorted files and directories list.
671 """
672
673 find_command = ['find', target_path] + (extra_args or [])
674 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700675 return common.RunAndCheckOutput(['sort'],
676 stdin=find_process.stdout,
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900677 verbose=False)
678
679
680def create_merged_package(temp_dir, framework_target_files, framework_item_list,
681 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700682 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700683 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800684
685 Args:
686 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700687 input target files packages, and also a scratch directory that we use for
688 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700689 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700690 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700691 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700692 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700693 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700694 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700695 vendor_target_files: The name of the zip archive containing the vendor
696 partial target files package.
697 vendor_item_list: The list of items to extract from the partial vendor
698 target files package as is, meaning these items will land in the output
699 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700700 target files package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900701 framework_misc_info_keys: The list of keys to obtain from the framework
702 instance of META/misc_info.txt. The remaining keys from the vendor
703 instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700704 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700705 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800706
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900707 Returns:
708 Path to merged package under temp directory.
709 """
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800710
Daniel Normand5d70ea2019-06-05 15:13:43 -0700711 # Create directory names that we'll use when we extract files from framework,
712 # and vendor, and for zipping the final output.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800713
Daniel Normand5d70ea2019-06-05 15:13:43 -0700714 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
715 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800716 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
717
Daniel Normand5d70ea2019-06-05 15:13:43 -0700718 # Extract "as is" items from the input framework partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800719 # We extract them directly into the output temporary directory since the
720 # items do not need special case processing.
721
Bill Peckham889b0c62019-02-21 18:53:37 -0800722 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700723 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800724 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700725 extract_item_list=framework_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800726
Daniel Normand5d70ea2019-06-05 15:13:43 -0700727 # Extract "as is" items from the input vendor partial target files package. We
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800728 # extract them directly into the output temporary directory since the items
729 # do not need special case processing.
730
Bill Peckham889b0c62019-02-21 18:53:37 -0800731 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700732 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800733 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700734 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800735
Daniel Normand5d70ea2019-06-05 15:13:43 -0700736 # Extract "special" items from the input framework partial target files
737 # package. We extract these items to different directory since they require
738 # special processing before they will end up in the output directory.
739
740 extract_items(
741 target_files=framework_target_files,
742 target_files_temp_dir=framework_target_files_temp_dir,
743 extract_item_list=FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST)
744
745 # Extract "special" items from the input vendor partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800746 # We extract these items to different directory since they require special
747 # processing before they will end up in the output directory.
748
Bill Peckham889b0c62019-02-21 18:53:37 -0800749 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700750 target_files=vendor_target_files,
751 target_files_temp_dir=vendor_target_files_temp_dir,
752 extract_item_list=VENDOR_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800753
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800754 # Now that the temporary directories contain all the extracted files, perform
755 # special case processing on any items that need it. After this function
756 # completes successfully, all the files we need to create the output target
757 # files package are in place.
758
Bill Peckham889b0c62019-02-21 18:53:37 -0800759 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700760 framework_target_files_temp_dir=framework_target_files_temp_dir,
761 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800762 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700763 framework_misc_info_keys=framework_misc_info_keys,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700764 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800765
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900766 return output_target_files_temp_dir
767
768
769def generate_images(target_files_dir, rebuild_recovery):
770 """Generate images from target files.
771
772 This function takes merged output temporary directory and create images
773 from it.
774
775 Args:
776 target_files_dir: Path to merged temp directory.
777 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
778 devices and write it to the system image.
779 """
780
781 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800782
Daniel Normana4911da2019-03-15 14:36:21 -0700783 add_img_args = ['--verbose']
784 if rebuild_recovery:
785 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900786 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800787
788 add_img_to_target_files.main(add_img_args)
789
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900790
791def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700792 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900793
794 Args:
795 target_dir: Path to the target file package which contains misc_info.txt for
796 detailed information for super image.
797 output_super_empty: If provided, copies a super_empty.img file from the
798 target files package to this path.
799 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700800 # Create super_empty.img using the merged misc_info.txt.
801
Daniel Norman4cc9df62019-07-18 10:11:07 -0700802 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700803
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900804 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
805 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700806
807 if use_dynamic_partitions != 'true' and output_super_empty:
808 raise ValueError(
809 'Building super_empty.img requires use_dynamic_partitions=true.')
810 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700811 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700812 build_super_image_args = [
813 misc_info_txt,
814 super_empty_img,
815 ]
816 build_super_image.main(build_super_image_args)
817
818 # Copy super_empty.img to the user-provided output_super_empty location.
819 if output_super_empty:
820 shutil.copyfile(super_empty_img, output_super_empty)
821
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700822
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900823def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700824 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900825
826 Args:
827 output_file: The name of the zip archive target files package.
828 source_dir: The target directory contains package to be archived.
829 temp_dir: Path to temporary directory for any intermediate files.
830 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800831 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900832 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700833 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800834
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900835 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700836 other_content = files_from_path(
837 source_dir,
838 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800839
Tao Bao2ad4b822019-06-27 16:52:12 -0700840 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800841 f.write(meta_content)
842 f.write(other_content)
843
844 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800845 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800846 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700847 '-o',
848 output_zip,
849 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900850 source_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700851 '-l',
852 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800853 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900854
855 logger.info('creating %s', output_file)
Bill Peckham889b0c62019-02-21 18:53:37 -0800856 common.RunAndWait(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900857 logger.info('finished creating %s', output_file)
858
859 return output_zip
860
861
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900862def merge_target_files(temp_dir, framework_target_files, framework_item_list,
863 framework_misc_info_keys, vendor_target_files,
864 vendor_item_list, output_target_files, output_dir,
865 output_item_list, output_ota, output_img,
866 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700867 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900868
869 This function takes framework and vendor target files packages as input,
870 performs various file extractions, special case processing, and finally
871 creates a merged zip archive as output.
872
873 Args:
874 temp_dir: The name of a directory we use when we extract items from the
875 input target files packages, and also a scratch directory that we use for
876 temporary files.
877 framework_target_files: The name of the zip archive containing the framework
878 partial target files package.
879 framework_item_list: The list of items to extract from the partial framework
880 target files package as is, meaning these items will land in the output
881 target files package exactly as they appear in the input partial framework
882 target files package.
883 framework_misc_info_keys: The list of keys to obtain from the framework
884 instance of META/misc_info.txt. The remaining keys from the vendor
885 instance.
886 vendor_target_files: The name of the zip archive containing the vendor
887 partial target files package.
888 vendor_item_list: The list of items to extract from the partial vendor
889 target files package as is, meaning these items will land in the output
890 target files package exactly as they appear in the input partial vendor
891 target files package.
892 output_target_files: The name of the output zip archive target files package
893 created by merging framework and vendor.
894 output_dir: The destination directory for saving merged files.
895 output_item_list: The list of items to copy into the output_dir.
896 output_ota: The name of the output zip archive ota package.
897 output_img: The name of the output zip archive img package.
898 output_super_empty: If provided, creates a super_empty.img file from the
899 merged target files package and saves it at this path.
900 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
901 devices and write it to the system image.
902 """
903
904 logger.info('starting: merge framework %s and vendor %s into output %s',
905 framework_target_files, vendor_target_files, output_target_files)
906
907 output_target_files_temp_dir = create_merged_package(
908 temp_dir, framework_target_files, framework_item_list,
909 vendor_target_files, vendor_item_list, framework_misc_info_keys,
910 rebuild_recovery)
911
912 generate_images(output_target_files_temp_dir, rebuild_recovery)
913
914 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
915
916 if output_img:
917 # Create the IMG package from the merged target files (before zipping, in
918 # order to avoid an unnecessary unzip and copy).
Daniel Norman4cc9df62019-07-18 10:11:07 -0700919 img_from_target_files.main([output_target_files_temp_dir, output_img])
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900920
921 # Finally, create the output target files zip archive and/or copy the
922 # output items to the output target files directory.
923
924 if output_dir:
925 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
926
927 if not output_target_files:
928 return
929
930 output_zip = create_target_files_archive(output_target_files,
931 output_target_files_temp_dir,
932 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800933
Daniel Norman3b64ce12019-04-16 16:11:35 -0700934 # Create the OTA package from the merged target files package.
935
936 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -0700937 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -0700938
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700939
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800940def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -0700941 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800942
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800943 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800944 directory. It also cleans up the temporary directory.
945
946 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700947 func: The function to call. Should accept one parameter, the path to the
948 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800949 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800950 """
951
952 # Create a temporary directory. This will serve as the parent of directories
953 # we use when we extract items from the input target files packages, and also
954 # a scratch directory that we use for temporary files.
955
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800956 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
957
958 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800959 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800960 finally:
961 if keep_tmp:
962 logger.info('keeping %s', temp_dir)
963 else:
964 common.Cleanup()
965
966
967def main():
968 """The main function.
969
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800970 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800971 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800972 """
973
974 common.InitLogging()
975
Bill Peckhamf753e152019-02-19 18:02:46 -0800976 def option_handler(o, a):
977 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700978 logger.warning(
979 '--system-target-files has been renamed to --framework-target-files')
980 OPTIONS.framework_target_files = a
981 elif o == '--framework-target-files':
982 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800983 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700984 logger.warning(
985 '--system-item-list has been renamed to --framework-item-list')
986 OPTIONS.framework_item_list = a
987 elif o == '--framework-item-list':
988 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800989 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700990 logger.warning('--system-misc-info-keys has been renamed to '
991 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700992 OPTIONS.framework_misc_info_keys = a
993 elif o == '--framework-misc-info-keys':
994 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800995 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700996 logger.warning(
997 '--other-target-files has been renamed to --vendor-target-files')
998 OPTIONS.vendor_target_files = a
999 elif o == '--vendor-target-files':
1000 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001001 elif o == '--other-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -07001002 logger.warning('--other-item-list has been renamed to --vendor-item-list')
1003 OPTIONS.vendor_item_list = a
1004 elif o == '--vendor-item-list':
1005 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001006 elif o == '--output-target-files':
1007 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001008 elif o == '--output-dir':
1009 OPTIONS.output_dir = a
1010 elif o == '--output-item-list':
1011 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001012 elif o == '--output-ota':
1013 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001014 elif o == '--output-img':
1015 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001016 elif o == '--output-super-empty':
1017 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -07001018 elif o == '--rebuild_recovery':
1019 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001020 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001021 OPTIONS.keep_tmp = True
1022 else:
1023 return False
1024 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001025
Bill Peckhamf753e152019-02-19 18:02:46 -08001026 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001027 sys.argv[1:],
1028 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001029 extra_long_opts=[
1030 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001031 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001032 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001033 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001034 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001035 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001036 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001037 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001038 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001039 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001040 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001041 'output-dir=',
1042 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001043 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001044 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001045 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001046 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001047 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001048 ],
1049 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001050
Tao Bao2ad4b822019-06-27 16:52:12 -07001051 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001052 if (args or OPTIONS.framework_target_files is None or
1053 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001054 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
1055 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001056 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001057 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001058
Tao Baoabb806b2019-08-06 10:32:32 -07001059 # Always turn on verbose logging.
1060 OPTIONS.verbose = True
1061
Daniel Normand5d70ea2019-06-05 15:13:43 -07001062 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001063 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001064 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001065 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001066
Daniel Normand5d70ea2019-06-05 15:13:43 -07001067 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001068 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001069 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001070 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001071 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001072
Daniel Normand5d70ea2019-06-05 15:13:43 -07001073 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001074 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001075 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001076 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001077
Daniel Normanfdb38812019-04-15 09:47:24 -07001078 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001079 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001080 else:
1081 output_item_list = None
1082
Daniel Normane5964522019-03-19 10:32:03 -07001083 if not validate_config_lists(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001084 framework_item_list=framework_item_list,
1085 framework_misc_info_keys=framework_misc_info_keys,
1086 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001087 sys.exit(1)
1088
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001089 call_func_with_temp_dir(
1090 lambda temp_dir: merge_target_files(
1091 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001092 framework_target_files=OPTIONS.framework_target_files,
1093 framework_item_list=framework_item_list,
1094 framework_misc_info_keys=framework_misc_info_keys,
1095 vendor_target_files=OPTIONS.vendor_target_files,
1096 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001097 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001098 output_dir=OPTIONS.output_dir,
1099 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001100 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001101 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001102 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001103 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001104
1105
1106if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001107 main()