blob: 916c8037442387e225fd137f357702a4fee28122 [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',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800120 'META/update_engine_config.txt',
121 'PRODUCT/*',
122 'ROOT/*',
123 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700124)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800125
Daniel Normand5d70ea2019-06-05 15:13:43 -0700126# FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
127# partial framework target files package that need some special processing, such
128# as some sort of combination with items from the partial vendor target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800129# package.
130
Daniel Normand5d70ea2019-06-05 15:13:43 -0700131FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800132
Daniel Normand5d70ea2019-06-05 15:13:43 -0700133# DEFAULT_FRAMEWORK_MISC_INFO_KEYS is a list of keys to obtain from the
134# framework instance of META/misc_info.txt. The remaining keys from the
135# vendor instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800136
Daniel Normand5d70ea2019-06-05 15:13:43 -0700137DEFAULT_FRAMEWORK_MISC_INFO_KEYS = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800138 'avb_system_hashtree_enable',
139 'avb_system_add_hashtree_footer_args',
140 'avb_system_key_path',
141 'avb_system_algorithm',
142 'avb_system_rollback_index_location',
143 'avb_product_hashtree_enable',
144 'avb_product_add_hashtree_footer_args',
Justin Yun6151e3f2019-06-25 15:58:13 +0900145 'avb_system_ext_hashtree_enable',
146 'avb_system_ext_add_hashtree_footer_args',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800147 'system_root_image',
148 'root_dir',
149 'ab_update',
150 'default_system_dev_certificate',
151 'system_size',
Daniel Normanedf12472019-05-22 10:47:08 -0700152)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800153
Daniel Normand5d70ea2019-06-05 15:13:43 -0700154# DEFAULT_VENDOR_ITEM_LIST is a list of items to extract from the partial
155# vendor target files package as is, meaning these items will land in the output
156# target files package exactly as they appear in the input partial vendor target
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800157# files package.
158
Daniel Normand5d70ea2019-06-05 15:13:43 -0700159DEFAULT_VENDOR_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800160 'META/boot_filesystem_config.txt',
161 'META/otakeys.txt',
162 'META/releasetools.py',
163 'META/vendor_filesystem_config.txt',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800164 'BOOT/*',
165 'DATA/*',
166 'ODM/*',
167 'OTA/android-info.txt',
168 'PREBUILT_IMAGES/*',
169 'RADIO/*',
170 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700171)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800172
Daniel Normand5d70ea2019-06-05 15:13:43 -0700173# VENDOR_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
174# partial vendor target files package that need some special processing, such as
175# some sort of combination with items from the partial framework target files
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800176# package.
177
Daniel Normand5d70ea2019-06-05 15:13:43 -0700178VENDOR_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Daniel Normanedf12472019-05-22 10:47:08 -0700179
180# The merge config lists should not attempt to extract items from both
181# builds for any of the following partitions. The partitions in
182# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
Daniel Normand5d70ea2019-06-05 15:13:43 -0700183# framework or vendor, but not both).
Daniel Normanedf12472019-05-22 10:47:08 -0700184
185SINGLE_BUILD_PARTITIONS = (
186 'BOOT/',
187 'DATA/',
188 'ODM/',
189 'PRODUCT/',
Justin Yun6151e3f2019-06-25 15:58:13 +0900190 'SYSTEM_EXT/',
Daniel Normanedf12472019-05-22 10:47:08 -0700191 'RADIO/',
192 'RECOVERY/',
193 'ROOT/',
194 'SYSTEM/',
195 'SYSTEM_OTHER/',
196 'VENDOR/',
197)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800198
199
Chris Grossfabf50a2019-05-02 12:42:09 -0700200def write_sorted_data(data, path):
Tao Bao2ad4b822019-06-27 16:52:12 -0700201 """Writes the sorted contents of either a list or dict to file.
Chris Grossfabf50a2019-05-02 12:42:09 -0700202
Tao Bao2ad4b822019-06-27 16:52:12 -0700203 This function sorts the contents of the list or dict and then writes the
204 resulting sorted contents to a file specified by path.
Chris Grossfabf50a2019-05-02 12:42:09 -0700205
206 Args:
207 data: The list or dict to sort and write.
208 path: Path to the file to write the sorted values to. The file at path will
209 be overridden if it exists.
210 """
211 with open(path, 'w') as output:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700212 for entry in sorted(data):
Chris Grossfabf50a2019-05-02 12:42:09 -0700213 out_str = '{}={}\n'.format(entry, data[entry]) if isinstance(
214 data, dict) else '{}\n'.format(entry)
215 output.write(out_str)
216
217
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800218def extract_items(target_files, target_files_temp_dir, extract_item_list):
Tao Bao2ad4b822019-06-27 16:52:12 -0700219 """Extracts items from target files to temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800220
221 This function extracts from the specified target files zip archive into the
222 specified temporary directory, the items specified in the extract item list.
223
224 Args:
225 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800226 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700227 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800228 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800229 """
230
231 logger.info('extracting from %s', target_files)
232
233 # Filter the extract_item_list to remove any items that do not exist in the
234 # zip file. Otherwise, the extraction step will fail.
235
Daniel Norman4cc9df62019-07-18 10:11:07 -0700236 with zipfile.ZipFile(target_files, allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800237 target_files_namelist = target_files_zipfile.namelist()
238
239 filtered_extract_item_list = []
240 for pattern in extract_item_list:
241 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
242 if not matching_namelist:
243 logger.warning('no match for %s', pattern)
244 else:
245 filtered_extract_item_list.append(pattern)
246
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800247 # Extract from target_files into target_files_temp_dir the
248 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800249
Daniel Normane5b134a2019-04-17 14:54:06 -0700250 common.UnzipToDir(target_files, target_files_temp_dir,
251 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800252
253
Daniel Normanfdb38812019-04-15 09:47:24 -0700254def copy_items(from_dir, to_dir, patterns):
255 """Similar to extract_items() except uses an input dir instead of zip."""
256 file_paths = []
257 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700258 file_paths.extend(
259 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
260 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700261
262 filtered_file_paths = set()
263 for pattern in patterns:
264 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
265
266 for file_path in filtered_file_paths:
267 original_file_path = os.path.join(from_dir, file_path)
268 copied_file_path = os.path.join(to_dir, file_path)
269 copied_file_dir = os.path.dirname(copied_file_path)
270 if not os.path.exists(copied_file_dir):
271 os.makedirs(copied_file_dir)
272 if os.path.islink(original_file_path):
273 os.symlink(os.readlink(original_file_path), copied_file_path)
274 else:
275 shutil.copyfile(original_file_path, copied_file_path)
276
277
Daniel Normand5d70ea2019-06-05 15:13:43 -0700278def validate_config_lists(framework_item_list, framework_misc_info_keys,
279 vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700280 """Performs validations on the merge config lists.
281
282 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700283 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700284 target files package as is.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700285 framework_misc_info_keys: A list of keys to obtain from the framework
286 instance of META/misc_info.txt. The remaining keys from the vendor
287 instance.
288 vendor_item_list: The list of items to extract from the partial vendor
289 target files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700290
291 Returns:
292 False if a validation fails, otherwise true.
293 """
Daniel Normanedf12472019-05-22 10:47:08 -0700294 has_error = False
295
Daniel Normand5d70ea2019-06-05 15:13:43 -0700296 default_combined_item_set = set(DEFAULT_FRAMEWORK_ITEM_LIST)
297 default_combined_item_set.update(DEFAULT_VENDOR_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700298
Daniel Normand5d70ea2019-06-05 15:13:43 -0700299 combined_item_set = set(framework_item_list)
300 combined_item_set.update(vendor_item_list)
Daniel Normane5964522019-03-19 10:32:03 -0700301
302 # Check that the merge config lists are not missing any item specified
303 # by the default config lists.
304 difference = default_combined_item_set.difference(combined_item_set)
305 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700306 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700307 logger.error('Please ensure missing items are in either the '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700308 'framework-item-list or vendor-item-list files provided to '
Daniel Normane5964522019-03-19 10:32:03 -0700309 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700310 has_error = True
311
312 for partition in SINGLE_BUILD_PARTITIONS:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700313 in_framework = any(
314 item.startswith(partition) for item in framework_item_list)
315 in_vendor = any(item.startswith(partition) for item in vendor_item_list)
316 if in_framework and in_vendor:
Daniel Normanedf12472019-05-22 10:47:08 -0700317 logger.error(
Tao Bao2ad4b822019-06-27 16:52:12 -0700318 'Cannot extract items from %s for both the framework and vendor'
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900319 ' builds. Please ensure only one merge config item list'
Tao Bao2ad4b822019-06-27 16:52:12 -0700320 ' includes %s.', partition, partition)
Daniel Normanedf12472019-05-22 10:47:08 -0700321 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700322
Daniel Normand5d70ea2019-06-05 15:13:43 -0700323 if ('dynamic_partition_list' in framework_misc_info_keys) or (
324 'super_partition_groups' in framework_misc_info_keys):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700325 logger.error('Dynamic partition misc info keys should come from '
Daniel Normand5d70ea2019-06-05 15:13:43 -0700326 'the vendor instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700327 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700328
Daniel Normanedf12472019-05-22 10:47:08 -0700329 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700330
331
Daniel Normand5d70ea2019-06-05 15:13:43 -0700332def process_ab_partitions_txt(framework_target_files_temp_dir,
333 vendor_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700334 output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700335 """Performs special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800336
Tao Bao2ad4b822019-06-27 16:52:12 -0700337 This function merges the contents of the META/ab_partitions.txt files from the
338 framework directory and the vendor directory, placing the merged result in the
339 output directory. The precondition in that the files are already extracted.
340 The post condition is that the output META/ab_partitions.txt contains the
341 merged content. The format for each ab_partitions.txt a one partition name per
342 line. The output file contains the union of the parition names.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800343
344 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700345 framework_target_files_temp_dir: The name of a directory containing the
346 special items extracted from the framework target files package.
347 vendor_target_files_temp_dir: The name of a directory containing the special
348 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700349 output_target_files_temp_dir: The name of a directory that will be used to
350 create the output target files package after all the special cases are
351 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800352 """
353
Daniel Normand5d70ea2019-06-05 15:13:43 -0700354 framework_ab_partitions_txt = os.path.join(framework_target_files_temp_dir,
355 'META', 'ab_partitions.txt')
356
357 vendor_ab_partitions_txt = os.path.join(vendor_target_files_temp_dir, 'META',
Daniel Normane5b134a2019-04-17 14:54:06 -0700358 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800359
Daniel Normand5d70ea2019-06-05 15:13:43 -0700360 with open(framework_ab_partitions_txt) as f:
361 framework_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800362
Daniel Normand5d70ea2019-06-05 15:13:43 -0700363 with open(vendor_ab_partitions_txt) as f:
364 vendor_ab_partitions = f.read().splitlines()
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800365
Daniel Normand5d70ea2019-06-05 15:13:43 -0700366 output_ab_partitions = set(framework_ab_partitions + vendor_ab_partitions)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800367
Daniel Normane5b134a2019-04-17 14:54:06 -0700368 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
369 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800370
Chris Grossfabf50a2019-05-02 12:42:09 -0700371 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800372
373
Bill Peckham364c1cc2019-03-29 18:27:23 -0700374def append_recovery_to_filesystem_config(output_target_files_temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700375 """Performs special processing for META/filesystem_config.txt.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700376
Tao Bao2ad4b822019-06-27 16:52:12 -0700377 This function appends recovery information to META/filesystem_config.txt so
378 that recovery patch regeneration will succeed.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700379
380 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700381 output_target_files_temp_dir: The name of a directory that will be used to
382 create the output target files package after all the special cases are
383 processed. We find filesystem_config.txt here.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700384 """
385
Daniel Normane5b134a2019-04-17 14:54:06 -0700386 filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
387 'filesystem_config.txt')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700388
389 with open(filesystem_config_txt, 'a') as f:
390 # TODO(bpeckham) this data is hard coded. It should be generated
391 # programmatically.
Daniel Normane5b134a2019-04-17 14:54:06 -0700392 f.write('system/bin/install-recovery.sh 0 0 750 '
393 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
394 f.write('system/recovery-from-boot.p 0 0 644 '
395 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
396 f.write('system/etc/recovery.img 0 0 440 '
397 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700398
399
Daniel Normand5d70ea2019-06-05 15:13:43 -0700400def process_misc_info_txt(framework_target_files_temp_dir,
401 vendor_target_files_temp_dir,
402 output_target_files_temp_dir,
403 framework_misc_info_keys):
Tao Bao2ad4b822019-06-27 16:52:12 -0700404 """Performs special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800405
406 This function merges the contents of the META/misc_info.txt files from the
Daniel Normand5d70ea2019-06-05 15:13:43 -0700407 framework directory and the vendor directory, placing the merged result in the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800408 output directory. The precondition in that the files are already extracted.
409 The post condition is that the output META/misc_info.txt contains the merged
410 content.
411
412 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700413 framework_target_files_temp_dir: The name of a directory containing the
414 special items extracted from the framework target files package.
415 vendor_target_files_temp_dir: The name of a directory containing the special
416 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700417 output_target_files_temp_dir: The name of a directory that will be used to
418 create the output target files package after all the special cases are
419 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700420 framework_misc_info_keys: A list of keys to obtain from the framework
421 instance of META/misc_info.txt. The remaining keys from the vendor
422 instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800423 """
424
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900425 misc_info_path = ['META', 'misc_info.txt']
426 framework_dict = common.LoadDictionaryFromFile(
427 os.path.join(framework_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800428
Daniel Normand5d70ea2019-06-05 15:13:43 -0700429 # We take most of the misc info from the vendor target files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800430
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900431 merged_dict = common.LoadDictionaryFromFile(
432 os.path.join(vendor_target_files_temp_dir, *misc_info_path))
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800433
Daniel Normand5d70ea2019-06-05 15:13:43 -0700434 # Replace certain values in merged_dict with values from
435 # framework_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800436
Daniel Normand5d70ea2019-06-05 15:13:43 -0700437 for key in framework_misc_info_keys:
438 merged_dict[key] = framework_dict[key]
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800439
Daniel Norman19b9fe92019-03-19 14:48:02 -0700440 # Merge misc info keys used for Dynamic Partitions.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700441 if (merged_dict.get('use_dynamic_partitions') == 'true') and (
442 framework_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700443 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700444 framework_dict=framework_dict,
445 vendor_dict=merged_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700446 size_prefix='super_',
447 size_suffix='_group_size',
448 list_prefix='super_',
449 list_suffix='_partition_list')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700450 merged_dict.update(merged_dynamic_partitions_dict)
Tao Bao48a2feb2019-06-28 11:00:05 -0700451 # Ensure that add_img_to_target_files rebuilds super split images for
452 # devices that retrofit dynamic partitions. This flag may have been set to
453 # false in the partial builds to prevent duplicate building of super.img.
Daniel Norman0bf940c2019-06-10 12:50:19 -0700454 merged_dict['build_super_partition'] = 'true'
Daniel Norman19b9fe92019-03-19 14:48:02 -0700455
Daniel Normand5d70ea2019-06-05 15:13:43 -0700456 # Replace <image>_selinux_fc values with framework or vendor file_contexts.bin
Daniel Norman72c626f2019-05-13 15:58:14 -0700457 # depending on which dictionary the key came from.
458 # Only the file basename is required because all selinux_fc properties are
459 # replaced with the full path to the file under META/ when misc_info.txt is
460 # loaded from target files for repacking. See common.py LoadInfoDict().
Daniel Normand5d70ea2019-06-05 15:13:43 -0700461 for key in merged_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700462 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700463 merged_dict[key] = 'vendor_file_contexts.bin'
464 for key in framework_dict:
Daniel Norman72c626f2019-05-13 15:58:14 -0700465 if key.endswith('_selinux_fc'):
Daniel Normand5d70ea2019-06-05 15:13:43 -0700466 merged_dict[key] = 'framework_file_contexts.bin'
Daniel Norman72c626f2019-05-13 15:58:14 -0700467
Daniel Normane5b134a2019-04-17 14:54:06 -0700468 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
469 'misc_info.txt')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700470 write_sorted_data(data=merged_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800471
472
Daniel Normand5d70ea2019-06-05 15:13:43 -0700473def process_dynamic_partitions_info_txt(framework_target_files_dir,
474 vendor_target_files_dir,
Daniel Normana61cde02019-05-03 14:19:13 -0700475 output_target_files_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700476 """Performs special processing for META/dynamic_partitions_info.txt.
Daniel Normana61cde02019-05-03 14:19:13 -0700477
478 This function merges the contents of the META/dynamic_partitions_info.txt
Daniel Normand5d70ea2019-06-05 15:13:43 -0700479 files from the framework directory and the vendor directory, placing the
480 merged result in the output directory.
Daniel Normana61cde02019-05-03 14:19:13 -0700481
Daniel Normand5d70ea2019-06-05 15:13:43 -0700482 This function does nothing if META/dynamic_partitions_info.txt from the vendor
Daniel Normana61cde02019-05-03 14:19:13 -0700483 directory does not exist.
484
485 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700486 framework_target_files_dir: The name of a directory containing the special
487 items extracted from the framework target files package.
488 vendor_target_files_dir: The name of a directory containing the special
489 items extracted from the vendor target files package.
Daniel Normana61cde02019-05-03 14:19:13 -0700490 output_target_files_dir: The name of a directory that will be used to create
491 the output target files package after all the special cases are processed.
492 """
493
494 if not os.path.exists(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700495 os.path.join(vendor_target_files_dir, 'META',
Daniel Normana61cde02019-05-03 14:19:13 -0700496 'dynamic_partitions_info.txt')):
497 return
498
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900499 dynamic_partitions_info_path = ['META', 'dynamic_partitions_info.txt']
Daniel Normana61cde02019-05-03 14:19:13 -0700500
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900501 framework_dynamic_partitions_dict = common.LoadDictionaryFromFile(
502 os.path.join(framework_target_files_dir, *dynamic_partitions_info_path))
503 vendor_dynamic_partitions_dict = common.LoadDictionaryFromFile(
504 os.path.join(vendor_target_files_dir, *dynamic_partitions_info_path))
Daniel Normana61cde02019-05-03 14:19:13 -0700505
Daniel Normanbfc51ef2019-07-24 14:34:54 -0700506 merged_dynamic_partitions_dict = common.MergeDynamicPartitionInfoDicts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700507 framework_dict=framework_dynamic_partitions_dict,
508 vendor_dict=vendor_dynamic_partitions_dict,
Daniel Normana61cde02019-05-03 14:19:13 -0700509 # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
510 include_dynamic_partition_list=False,
511 size_suffix='_size',
512 list_suffix='_partition_list')
513
514 output_dynamic_partitions_info_txt = os.path.join(
515 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700516 write_sorted_data(
517 data=merged_dynamic_partitions_dict,
518 path=output_dynamic_partitions_info_txt)
519
520
Daniel Normand5d70ea2019-06-05 15:13:43 -0700521def process_apex_keys_apk_certs_common(framework_target_files_dir,
522 vendor_target_files_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700523 output_target_files_dir, file_name):
Tao Bao2ad4b822019-06-27 16:52:12 -0700524 """Performs special processing for META/apexkeys.txt or META/apkcerts.txt.
Chris Grossfabf50a2019-05-02 12:42:09 -0700525
526 This function merges the contents of the META/apexkeys.txt or
Tao Bao2ad4b822019-06-27 16:52:12 -0700527 META/apkcerts.txt files from the framework directory and the vendor directory,
528 placing the merged result in the output directory. The precondition in that
529 the files are already extracted. The post condition is that the output
530 META/apexkeys.txt or META/apkcerts.txt contains the merged content.
Chris Grossfabf50a2019-05-02 12:42:09 -0700531
532 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700533 framework_target_files_dir: The name of a directory containing the special
534 items extracted from the framework target files package.
535 vendor_target_files_dir: The name of a directory containing the special
536 items extracted from the vendor target files package.
Chris Grossfabf50a2019-05-02 12:42:09 -0700537 output_target_files_dir: The name of a directory that will be used to create
538 the output target files package after all the special cases are processed.
539 file_name: The name of the file to merge. One of apkcerts.txt or
540 apexkeys.txt.
541 """
542
543 def read_helper(d):
544 temp = {}
545 file_path = os.path.join(d, 'META', file_name)
546 with open(file_path) as f:
547 for line in f:
548 if line.strip():
549 temp[line.split()[0]] = line.strip()
550 return temp
551
Daniel Normand5d70ea2019-06-05 15:13:43 -0700552 framework_dict = read_helper(framework_target_files_dir)
553 vendor_dict = read_helper(vendor_target_files_dir)
Chris Grossfabf50a2019-05-02 12:42:09 -0700554
Daniel Normand5d70ea2019-06-05 15:13:43 -0700555 for key in framework_dict:
556 if key in vendor_dict and vendor_dict[key] != framework_dict[key]:
Chris Grossfabf50a2019-05-02 12:42:09 -0700557 raise ValueError('Conflicting entries found in %s:\n %s and\n %s' %
Daniel Normand5d70ea2019-06-05 15:13:43 -0700558 (file_name, framework_dict[key], vendor_dict[key]))
559 vendor_dict[key] = framework_dict[key]
Chris Grossfabf50a2019-05-02 12:42:09 -0700560
561 output_file = os.path.join(output_target_files_dir, 'META', file_name)
562
Daniel Normand5d70ea2019-06-05 15:13:43 -0700563 write_sorted_data(data=vendor_dict.values(), path=output_file)
Daniel Normana61cde02019-05-03 14:19:13 -0700564
565
Daniel Normand5d70ea2019-06-05 15:13:43 -0700566def copy_file_contexts(framework_target_files_dir, vendor_target_files_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700567 output_target_files_dir):
568 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normand5d70ea2019-06-05 15:13:43 -0700569 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
570 'framework_file_contexts.bin')
571 if not os.path.exists(framework_fc_path):
572 framework_fc_path = os.path.join(framework_target_files_dir, 'META',
573 'file_contexts.bin')
574 if not os.path.exists(framework_fc_path):
575 raise ValueError('Missing framework file_contexts.bin.')
576 shutil.copyfile(
577 framework_fc_path,
578 os.path.join(output_target_files_dir, 'META',
579 'framework_file_contexts.bin'))
580
581 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
582 'vendor_file_contexts.bin')
583 if not os.path.exists(vendor_fc_path):
584 vendor_fc_path = os.path.join(vendor_target_files_dir, 'META',
Daniel Normanedf12472019-05-22 10:47:08 -0700585 'file_contexts.bin')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700586 if not os.path.exists(vendor_fc_path):
587 raise ValueError('Missing vendor file_contexts.bin.')
Daniel Norman72c626f2019-05-13 15:58:14 -0700588 shutil.copyfile(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700589 vendor_fc_path,
590 os.path.join(output_target_files_dir, 'META', 'vendor_file_contexts.bin'))
Daniel Norman72c626f2019-05-13 15:58:14 -0700591
592
Daniel Normand5d70ea2019-06-05 15:13:43 -0700593def process_special_cases(framework_target_files_temp_dir,
594 vendor_target_files_temp_dir,
595 output_target_files_temp_dir,
596 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700597 """Performs special-case processing for certain target files items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800598
599 Certain files in the output target files package require special-case
600 processing. This function performs all that special-case processing.
601
602 Args:
Daniel Normand5d70ea2019-06-05 15:13:43 -0700603 framework_target_files_temp_dir: The name of a directory containing the
604 special items extracted from the framework target files package.
605 vendor_target_files_temp_dir: The name of a directory containing the special
606 items extracted from the vendor target files package.
Daniel Normane5b134a2019-04-17 14:54:06 -0700607 output_target_files_temp_dir: The name of a directory that will be used to
608 create the output target files package after all the special cases are
609 processed.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700610 framework_misc_info_keys: A list of keys to obtain from the framework
611 instance of META/misc_info.txt. The remaining keys from the vendor
612 instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700613 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700614 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800615 """
616
Daniel Normand5d70ea2019-06-05 15:13:43 -0700617 if 'ab_update' in framework_misc_info_keys:
Bill Peckham364c1cc2019-03-29 18:27:23 -0700618 process_ab_partitions_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700619 framework_target_files_temp_dir=framework_target_files_temp_dir,
620 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700621 output_target_files_temp_dir=output_target_files_temp_dir)
622
623 if rebuild_recovery:
624 append_recovery_to_filesystem_config(
625 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800626
Daniel Norman72c626f2019-05-13 15:58:14 -0700627 copy_file_contexts(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700628 framework_target_files_dir=framework_target_files_temp_dir,
629 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman72c626f2019-05-13 15:58:14 -0700630 output_target_files_dir=output_target_files_temp_dir)
631
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800632 process_misc_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700633 framework_target_files_temp_dir=framework_target_files_temp_dir,
634 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800635 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700636 framework_misc_info_keys=framework_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800637
Daniel Normana61cde02019-05-03 14:19:13 -0700638 process_dynamic_partitions_info_txt(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700639 framework_target_files_dir=framework_target_files_temp_dir,
640 vendor_target_files_dir=vendor_target_files_temp_dir,
Daniel Norman714bd122019-05-08 16:20:02 -0700641 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700642
Chris Grossfabf50a2019-05-02 12:42:09 -0700643 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700644 framework_target_files_dir=framework_target_files_temp_dir,
645 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700646 output_target_files_dir=output_target_files_temp_dir,
647 file_name='apkcerts.txt')
648
649 process_apex_keys_apk_certs_common(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700650 framework_target_files_dir=framework_target_files_temp_dir,
651 vendor_target_files_dir=vendor_target_files_temp_dir,
Chris Grossfabf50a2019-05-02 12:42:09 -0700652 output_target_files_dir=output_target_files_temp_dir,
653 file_name='apexkeys.txt')
654
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800655
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900656def files_from_path(target_path, extra_args=None):
Tao Bao2ad4b822019-06-27 16:52:12 -0700657 """Gets files under given path.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800658
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900659 Get (sub)files from given target path and return sorted list.
660
661 Args:
662 target_path: Target path to get subfiles.
663 extra_args: List of extra argument for find command. Optional.
664
665 Returns:
666 Sorted files and directories list.
667 """
668
669 find_command = ['find', target_path] + (extra_args or [])
670 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700671 return common.RunAndCheckOutput(['sort'],
672 stdin=find_process.stdout,
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900673 verbose=False)
674
675
676def create_merged_package(temp_dir, framework_target_files, framework_item_list,
677 vendor_target_files, vendor_item_list,
Daniel Norman4cc9df62019-07-18 10:11:07 -0700678 framework_misc_info_keys, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700679 """Merges two target files packages into one target files structure.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800680
681 Args:
682 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700683 input target files packages, and also a scratch directory that we use for
684 temporary files.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700685 framework_target_files: The name of the zip archive containing the framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700686 partial target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700687 framework_item_list: The list of items to extract from the partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700688 target files package as is, meaning these items will land in the output
Daniel Normand5d70ea2019-06-05 15:13:43 -0700689 target files package exactly as they appear in the input partial framework
Daniel Normane5b134a2019-04-17 14:54:06 -0700690 target files package.
Daniel Normand5d70ea2019-06-05 15:13:43 -0700691 vendor_target_files: The name of the zip archive containing the vendor
692 partial target files package.
693 vendor_item_list: The list of items to extract from the partial vendor
694 target files package as is, meaning these items will land in the output
695 target files package exactly as they appear in the input partial vendor
Daniel Normane5b134a2019-04-17 14:54:06 -0700696 target files package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900697 framework_misc_info_keys: The list of keys to obtain from the framework
698 instance of META/misc_info.txt. The remaining keys from the vendor
699 instance.
Daniel Normana4911da2019-03-15 14:36:21 -0700700 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700701 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800702
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900703 Returns:
704 Path to merged package under temp directory.
705 """
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800706
Daniel Normand5d70ea2019-06-05 15:13:43 -0700707 # Create directory names that we'll use when we extract files from framework,
708 # and vendor, and for zipping the final output.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800709
Daniel Normand5d70ea2019-06-05 15:13:43 -0700710 framework_target_files_temp_dir = os.path.join(temp_dir, 'framework')
711 vendor_target_files_temp_dir = os.path.join(temp_dir, 'vendor')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800712 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
713
Daniel Normand5d70ea2019-06-05 15:13:43 -0700714 # Extract "as is" items from the input framework partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800715 # We extract them directly into the output temporary directory since the
716 # items do not need special case processing.
717
Bill Peckham889b0c62019-02-21 18:53:37 -0800718 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700719 target_files=framework_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800720 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700721 extract_item_list=framework_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800722
Daniel Normand5d70ea2019-06-05 15:13:43 -0700723 # Extract "as is" items from the input vendor partial target files package. We
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800724 # extract them directly into the output temporary directory since the items
725 # do not need special case processing.
726
Bill Peckham889b0c62019-02-21 18:53:37 -0800727 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700728 target_files=vendor_target_files,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800729 target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700730 extract_item_list=vendor_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800731
Daniel Normand5d70ea2019-06-05 15:13:43 -0700732 # Extract "special" items from the input framework partial target files
733 # package. We extract these items to different directory since they require
734 # special processing before they will end up in the output directory.
735
736 extract_items(
737 target_files=framework_target_files,
738 target_files_temp_dir=framework_target_files_temp_dir,
739 extract_item_list=FRAMEWORK_EXTRACT_SPECIAL_ITEM_LIST)
740
741 # Extract "special" items from the input vendor partial target files package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800742 # We extract these items to different directory since they require special
743 # processing before they will end up in the output directory.
744
Bill Peckham889b0c62019-02-21 18:53:37 -0800745 extract_items(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700746 target_files=vendor_target_files,
747 target_files_temp_dir=vendor_target_files_temp_dir,
748 extract_item_list=VENDOR_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800749
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800750 # Now that the temporary directories contain all the extracted files, perform
751 # special case processing on any items that need it. After this function
752 # completes successfully, all the files we need to create the output target
753 # files package are in place.
754
Bill Peckham889b0c62019-02-21 18:53:37 -0800755 process_special_cases(
Daniel Normand5d70ea2019-06-05 15:13:43 -0700756 framework_target_files_temp_dir=framework_target_files_temp_dir,
757 vendor_target_files_temp_dir=vendor_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800758 output_target_files_temp_dir=output_target_files_temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -0700759 framework_misc_info_keys=framework_misc_info_keys,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700760 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800761
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900762 return output_target_files_temp_dir
763
764
765def generate_images(target_files_dir, rebuild_recovery):
766 """Generate images from target files.
767
768 This function takes merged output temporary directory and create images
769 from it.
770
771 Args:
772 target_files_dir: Path to merged temp directory.
773 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
774 devices and write it to the system image.
775 """
776
777 # Regenerate IMAGES in the target directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800778
Daniel Normana4911da2019-03-15 14:36:21 -0700779 add_img_args = ['--verbose']
Paul Trautrimbc3600c2019-08-13 18:07:03 +0900780 add_img_args.append('--add_missing')
Daniel Normana4911da2019-03-15 14:36:21 -0700781 if rebuild_recovery:
782 add_img_args.append('--rebuild_recovery')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900783 add_img_args.append(target_files_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800784
785 add_img_to_target_files.main(add_img_args)
786
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900787
788def generate_super_empty_image(target_dir, output_super_empty):
Tao Bao2ad4b822019-06-27 16:52:12 -0700789 """Generates super_empty image from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900790
791 Args:
792 target_dir: Path to the target file package which contains misc_info.txt for
793 detailed information for super image.
794 output_super_empty: If provided, copies a super_empty.img file from the
795 target files package to this path.
796 """
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700797 # Create super_empty.img using the merged misc_info.txt.
798
Daniel Norman4cc9df62019-07-18 10:11:07 -0700799 misc_info_txt = os.path.join(target_dir, 'META', 'misc_info.txt')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700800
Kiyoung Kimebe7c9c2019-06-25 17:09:55 +0900801 use_dynamic_partitions = common.LoadDictionaryFromFile(misc_info_txt).get(
802 'use_dynamic_partitions')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700803
804 if use_dynamic_partitions != 'true' and output_super_empty:
805 raise ValueError(
806 'Building super_empty.img requires use_dynamic_partitions=true.')
807 elif use_dynamic_partitions == 'true':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700808 super_empty_img = os.path.join(target_dir, 'IMAGES', 'super_empty.img')
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700809 build_super_image_args = [
810 misc_info_txt,
811 super_empty_img,
812 ]
813 build_super_image.main(build_super_image_args)
814
815 # Copy super_empty.img to the user-provided output_super_empty location.
816 if output_super_empty:
817 shutil.copyfile(super_empty_img, output_super_empty)
818
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700819
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900820def create_target_files_archive(output_file, source_dir, temp_dir):
Tao Bao2ad4b822019-06-27 16:52:12 -0700821 """Creates archive from target package.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900822
823 Args:
824 output_file: The name of the zip archive target files package.
825 source_dir: The target directory contains package to be archived.
826 temp_dir: Path to temporary directory for any intermediate files.
827 """
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800828 output_target_files_list = os.path.join(temp_dir, 'output.list')
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900829 output_zip = os.path.abspath(output_file)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700830 output_target_files_meta_dir = os.path.join(source_dir, 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800831
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900832 meta_content = files_from_path(output_target_files_meta_dir)
Daniel Norman4cc9df62019-07-18 10:11:07 -0700833 other_content = files_from_path(
834 source_dir,
835 ['-path', output_target_files_meta_dir, '-prune', '-o', '-print'])
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800836
Tao Bao2ad4b822019-06-27 16:52:12 -0700837 with open(output_target_files_list, 'w') as f:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800838 f.write(meta_content)
839 f.write(other_content)
840
841 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800842 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800843 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700844 '-o',
845 output_zip,
846 '-C',
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900847 source_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700848 '-l',
849 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800850 ]
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900851
852 logger.info('creating %s', output_file)
Bill Peckham889b0c62019-02-21 18:53:37 -0800853 common.RunAndWait(command, verbose=True)
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900854 logger.info('finished creating %s', output_file)
855
856 return output_zip
857
858
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900859def merge_target_files(temp_dir, framework_target_files, framework_item_list,
860 framework_misc_info_keys, vendor_target_files,
861 vendor_item_list, output_target_files, output_dir,
862 output_item_list, output_ota, output_img,
863 output_super_empty, rebuild_recovery):
Tao Bao2ad4b822019-06-27 16:52:12 -0700864 """Merges two target files packages together.
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900865
866 This function takes framework and vendor target files packages as input,
867 performs various file extractions, special case processing, and finally
868 creates a merged zip archive as output.
869
870 Args:
871 temp_dir: The name of a directory we use when we extract items from the
872 input target files packages, and also a scratch directory that we use for
873 temporary files.
874 framework_target_files: The name of the zip archive containing the framework
875 partial target files package.
876 framework_item_list: The list of items to extract from the partial framework
877 target files package as is, meaning these items will land in the output
878 target files package exactly as they appear in the input partial framework
879 target files package.
880 framework_misc_info_keys: The list of keys to obtain from the framework
881 instance of META/misc_info.txt. The remaining keys from the vendor
882 instance.
883 vendor_target_files: The name of the zip archive containing the vendor
884 partial target files package.
885 vendor_item_list: The list of items to extract from the partial vendor
886 target files package as is, meaning these items will land in the output
887 target files package exactly as they appear in the input partial vendor
888 target files package.
889 output_target_files: The name of the output zip archive target files package
890 created by merging framework and vendor.
891 output_dir: The destination directory for saving merged files.
892 output_item_list: The list of items to copy into the output_dir.
893 output_ota: The name of the output zip archive ota package.
894 output_img: The name of the output zip archive img package.
895 output_super_empty: If provided, creates a super_empty.img file from the
896 merged target files package and saves it at this path.
897 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
898 devices and write it to the system image.
899 """
900
901 logger.info('starting: merge framework %s and vendor %s into output %s',
902 framework_target_files, vendor_target_files, output_target_files)
903
904 output_target_files_temp_dir = create_merged_package(
905 temp_dir, framework_target_files, framework_item_list,
906 vendor_target_files, vendor_item_list, framework_misc_info_keys,
907 rebuild_recovery)
908
909 generate_images(output_target_files_temp_dir, rebuild_recovery)
910
911 generate_super_empty_image(output_target_files_temp_dir, output_super_empty)
912
913 if output_img:
914 # Create the IMG package from the merged target files (before zipping, in
915 # order to avoid an unnecessary unzip and copy).
Daniel Norman4cc9df62019-07-18 10:11:07 -0700916 img_from_target_files.main([output_target_files_temp_dir, output_img])
Kiyoung Kim7cbeda72019-06-28 13:26:04 +0900917
918 # Finally, create the output target files zip archive and/or copy the
919 # output items to the output target files directory.
920
921 if output_dir:
922 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
923
924 if not output_target_files:
925 return
926
927 output_zip = create_target_files_archive(output_target_files,
928 output_target_files_temp_dir,
929 temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800930
Daniel Norman3b64ce12019-04-16 16:11:35 -0700931 # Create the OTA package from the merged target files package.
932
933 if output_ota:
Daniel Norman4cc9df62019-07-18 10:11:07 -0700934 ota_from_target_files.main([output_zip, output_ota])
Daniel Norman3b64ce12019-04-16 16:11:35 -0700935
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700936
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800937def call_func_with_temp_dir(func, keep_tmp):
Tao Bao2ad4b822019-06-27 16:52:12 -0700938 """Manages the creation and cleanup of the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800939
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800940 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800941 directory. It also cleans up the temporary directory.
942
943 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700944 func: The function to call. Should accept one parameter, the path to the
945 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800946 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800947 """
948
949 # Create a temporary directory. This will serve as the parent of directories
950 # we use when we extract items from the input target files packages, and also
951 # a scratch directory that we use for temporary files.
952
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800953 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
954
955 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800956 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800957 finally:
958 if keep_tmp:
959 logger.info('keeping %s', temp_dir)
960 else:
961 common.Cleanup()
962
963
964def main():
965 """The main function.
966
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800967 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800968 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800969 """
970
971 common.InitLogging()
972
Bill Peckhamf753e152019-02-19 18:02:46 -0800973 def option_handler(o, a):
974 if o == '--system-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700975 logger.warning(
976 '--system-target-files has been renamed to --framework-target-files')
977 OPTIONS.framework_target_files = a
978 elif o == '--framework-target-files':
979 OPTIONS.framework_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800980 elif o == '--system-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700981 logger.warning(
982 '--system-item-list has been renamed to --framework-item-list')
983 OPTIONS.framework_item_list = a
984 elif o == '--framework-item-list':
985 OPTIONS.framework_item_list = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800986 elif o == '--system-misc-info-keys':
Daniel Norman4cc9df62019-07-18 10:11:07 -0700987 logger.warning('--system-misc-info-keys has been renamed to '
988 '--framework-misc-info-keys')
Daniel Normand5d70ea2019-06-05 15:13:43 -0700989 OPTIONS.framework_misc_info_keys = a
990 elif o == '--framework-misc-info-keys':
991 OPTIONS.framework_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800992 elif o == '--other-target-files':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700993 logger.warning(
994 '--other-target-files has been renamed to --vendor-target-files')
995 OPTIONS.vendor_target_files = a
996 elif o == '--vendor-target-files':
997 OPTIONS.vendor_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800998 elif o == '--other-item-list':
Daniel Normand5d70ea2019-06-05 15:13:43 -0700999 logger.warning('--other-item-list has been renamed to --vendor-item-list')
1000 OPTIONS.vendor_item_list = a
1001 elif o == '--vendor-item-list':
1002 OPTIONS.vendor_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -08001003 elif o == '--output-target-files':
1004 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -07001005 elif o == '--output-dir':
1006 OPTIONS.output_dir = a
1007 elif o == '--output-item-list':
1008 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -07001009 elif o == '--output-ota':
1010 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001011 elif o == '--output-img':
1012 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -07001013 elif o == '--output-super-empty':
1014 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -07001015 elif o == '--rebuild_recovery':
1016 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001017 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001018 OPTIONS.keep_tmp = True
1019 else:
1020 return False
1021 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001022
Bill Peckhamf753e152019-02-19 18:02:46 -08001023 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001024 sys.argv[1:],
1025 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001026 extra_long_opts=[
1027 'system-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001028 'framework-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001029 'system-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001030 'framework-item-list=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001031 'system-misc-info-keys=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001032 'framework-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001033 'other-target-files=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001034 'vendor-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001035 'other-item-list=',
Daniel Normand5d70ea2019-06-05 15:13:43 -07001036 'vendor-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001037 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001038 'output-dir=',
1039 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001040 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001041 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001042 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001043 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001044 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001045 ],
1046 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001047
Tao Bao2ad4b822019-06-27 16:52:12 -07001048 # pylint: disable=too-many-boolean-expressions
Daniel Normand5d70ea2019-06-05 15:13:43 -07001049 if (args or OPTIONS.framework_target_files is None or
1050 OPTIONS.vendor_target_files is None or
Daniel Normane5b134a2019-04-17 14:54:06 -07001051 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
1052 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001053 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001054 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001055
Tao Baoabb806b2019-08-06 10:32:32 -07001056 # Always turn on verbose logging.
1057 OPTIONS.verbose = True
1058
Daniel Normand5d70ea2019-06-05 15:13:43 -07001059 if OPTIONS.framework_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001060 framework_item_list = common.LoadListFromFile(OPTIONS.framework_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001061 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001062 framework_item_list = DEFAULT_FRAMEWORK_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001063
Daniel Normand5d70ea2019-06-05 15:13:43 -07001064 if OPTIONS.framework_misc_info_keys:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001065 framework_misc_info_keys = common.LoadListFromFile(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001066 OPTIONS.framework_misc_info_keys)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001067 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001068 framework_misc_info_keys = DEFAULT_FRAMEWORK_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001069
Daniel Normand5d70ea2019-06-05 15:13:43 -07001070 if OPTIONS.vendor_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001071 vendor_item_list = common.LoadListFromFile(OPTIONS.vendor_item_list)
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001072 else:
Daniel Normand5d70ea2019-06-05 15:13:43 -07001073 vendor_item_list = DEFAULT_VENDOR_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001074
Daniel Normanfdb38812019-04-15 09:47:24 -07001075 if OPTIONS.output_item_list:
Daniel Norman4cc9df62019-07-18 10:11:07 -07001076 output_item_list = common.LoadListFromFile(OPTIONS.output_item_list)
Daniel Normanfdb38812019-04-15 09:47:24 -07001077 else:
1078 output_item_list = None
1079
Daniel Normane5964522019-03-19 10:32:03 -07001080 if not validate_config_lists(
Daniel Normand5d70ea2019-06-05 15:13:43 -07001081 framework_item_list=framework_item_list,
1082 framework_misc_info_keys=framework_misc_info_keys,
1083 vendor_item_list=vendor_item_list):
Daniel Normane5964522019-03-19 10:32:03 -07001084 sys.exit(1)
1085
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001086 call_func_with_temp_dir(
1087 lambda temp_dir: merge_target_files(
1088 temp_dir=temp_dir,
Daniel Normand5d70ea2019-06-05 15:13:43 -07001089 framework_target_files=OPTIONS.framework_target_files,
1090 framework_item_list=framework_item_list,
1091 framework_misc_info_keys=framework_misc_info_keys,
1092 vendor_target_files=OPTIONS.vendor_target_files,
1093 vendor_item_list=vendor_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001094 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001095 output_dir=OPTIONS.output_dir,
1096 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001097 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001098 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001099 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001100 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001101
1102
1103if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001104 main()