blob: f900b1227403a16942e648d33b701952422a3c7e [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 Normane5b134a2019-04-17 14:54:06 -070016"""This script merges two partial target files packages.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080017
Daniel Normane5b134a2019-04-17 14:54:06 -070018One package contains system files, and the other contains non-system files.
19It produces a complete target files package that can be used to generate an
20OTA package.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080021
22Usage: merge_target_files.py [args]
23
24 --system-target-files system-target-files-zip-archive
25 The input target files package containing system bits. This is a zip
26 archive.
27
Daniel Norman2c99c5b2019-03-07 13:01:48 -080028 --system-item-list system-item-list-file
29 The optional path to a newline-separated config file that replaces the
Daniel Normanedf12472019-05-22 10:47:08 -070030 contents of DEFAULT_SYSTEM_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080031
32 --system-misc-info-keys system-misc-info-keys-file
33 The optional path to a newline-separated config file that replaces the
Daniel Normanedf12472019-05-22 10:47:08 -070034 contents of DEFAULT_SYSTEM_MISC_INFO_KEYS if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080035
Bill Peckhame9eb5f92019-02-01 15:52:10 -080036 --other-target-files other-target-files-zip-archive
37 The input target files package containing other bits. This is a zip
38 archive.
39
Daniel Norman2c99c5b2019-03-07 13:01:48 -080040 --other-item-list other-item-list-file
41 The optional path to a newline-separated config file that replaces the
Daniel Normanedf12472019-05-22 10:47:08 -070042 contents of DEFAULT_OTHER_ITEM_LIST if provided.
Daniel Norman2c99c5b2019-03-07 13:01:48 -080043
Bill Peckhame9eb5f92019-02-01 15:52:10 -080044 --output-target-files output-target-files-package
Daniel Normanfdb38812019-04-15 09:47:24 -070045 If provided, the output merged target files package. Also a zip archive.
46
47 --output-dir output-directory
48 If provided, the destination directory for saving merged files. Requires
49 the --output-item-list flag.
50 Can be provided alongside --output-target-files, or by itself.
51
52 --output-item-list output-item-list-file.
53 The optional path to a newline-separated config file that specifies the
54 file patterns to copy into the --output-dir. Required if providing
55 the --output-dir flag.
Daniel Normana4911da2019-03-15 14:36:21 -070056
Daniel Norman3b64ce12019-04-16 16:11:35 -070057 --output-ota output-ota-package
58 The output ota package. This is a zip archive. Use of this flag may
59 require passing the --path common flag; see common.py.
60
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070061 --output-img output-img-package
62 The output img package, suitable for use with 'fastboot update'. Use of
63 this flag may require passing the --path common flag; see common.py.
64
Daniel Normanf0318252019-04-15 11:34:56 -070065 --output-super-empty output-super-empty-image
66 If provided, creates a super_empty.img file from the merged target
67 files package and saves it at this path.
68
Daniel Normana4911da2019-03-15 14:36:21 -070069 --rebuild_recovery
70 Rebuild the recovery patch used by non-A/B devices and write it to the
71 system image.
Bill Peckham364c1cc2019-03-29 18:27:23 -070072
73 --keep-tmp
74 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080075"""
76
77from __future__ import print_function
78
Bill Peckhame9eb5f92019-02-01 15:52:10 -080079import fnmatch
80import logging
81import os
Daniel Normanfdb38812019-04-15 09:47:24 -070082import shutil
Bill Peckham540d91a2019-04-25 14:18:16 -070083import subprocess
Bill Peckhame9eb5f92019-02-01 15:52:10 -080084import sys
85import zipfile
86
Bill Peckhame9eb5f92019-02-01 15:52:10 -080087import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070088import build_super_image
89import common
Daniel Norman1bd2a1d2019-04-18 12:32:18 -070090import img_from_target_files
Daniel Norman3b64ce12019-04-16 16:11:35 -070091import ota_from_target_files
Bill Peckhame9eb5f92019-02-01 15:52:10 -080092
93logger = logging.getLogger(__name__)
94OPTIONS = common.OPTIONS
95OPTIONS.verbose = True
Bill Peckhamf753e152019-02-19 18:02:46 -080096OPTIONS.system_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080097OPTIONS.system_item_list = None
98OPTIONS.system_misc_info_keys = None
Bill Peckhamf753e152019-02-19 18:02:46 -080099OPTIONS.other_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800100OPTIONS.other_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -0800101OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -0700102OPTIONS.output_dir = None
103OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -0700104OPTIONS.output_ota = None
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700105OPTIONS.output_img = None
Daniel Normanf0318252019-04-15 11:34:56 -0700106OPTIONS.output_super_empty = None
Daniel Normana4911da2019-03-15 14:36:21 -0700107OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800108OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800109
Daniel Normanedf12472019-05-22 10:47:08 -0700110# DEFAULT_SYSTEM_ITEM_LIST is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800111# system target files package as is, meaning these items will land in the
112# output target files package exactly as they appear in the input partial
113# system target files package.
114
Daniel Normanedf12472019-05-22 10:47:08 -0700115DEFAULT_SYSTEM_ITEM_LIST = (
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800116 'META/apkcerts.txt',
117 'META/filesystem_config.txt',
118 'META/root_filesystem_config.txt',
119 'META/system_manifest.xml',
120 'META/system_matrix.xml',
121 'META/update_engine_config.txt',
122 'PRODUCT/*',
123 'ROOT/*',
124 'SYSTEM/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700125)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800126
Daniel Normanedf12472019-05-22 10:47:08 -0700127# SYSTEM_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800128# partial system target files package that need some special processing, such
129# as some sort of combination with items from the partial other target files
130# package.
131
Daniel Normanedf12472019-05-22 10:47:08 -0700132SYSTEM_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800133
Daniel Normanedf12472019-05-22 10:47:08 -0700134# DEFAULT_SYSTEM_MISC_INFO_KEYS is a list of keys to obtain from the system
Daniel Normane5b134a2019-04-17 14:54:06 -0700135# instance of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800136
Daniel Normanedf12472019-05-22 10:47:08 -0700137DEFAULT_SYSTEM_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',
145 'avb_product_services_hashtree_enable',
146 'avb_product_services_add_hashtree_footer_args',
147 '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 Normanedf12472019-05-22 10:47:08 -0700154# DEFAULT_OTHER_ITEM_LIST is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800155# other 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 other target
157# files package.
158
Daniel Normanedf12472019-05-22 10:47:08 -0700159DEFAULT_OTHER_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',
164 'META/vendor_manifest.xml',
165 'META/vendor_matrix.xml',
166 'BOOT/*',
167 'DATA/*',
168 'ODM/*',
169 'OTA/android-info.txt',
170 'PREBUILT_IMAGES/*',
171 'RADIO/*',
172 'VENDOR/*',
Daniel Normanedf12472019-05-22 10:47:08 -0700173)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800174
Daniel Normanedf12472019-05-22 10:47:08 -0700175# OTHER_EXTRACT_SPECIAL_ITEM_LIST is a list of items to extract from the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800176# partial other target files package that need some special processing, such as
177# some sort of combination with items from the partial system target files
178# package.
179
Daniel Normanedf12472019-05-22 10:47:08 -0700180OTHER_EXTRACT_SPECIAL_ITEM_LIST = ('META/*',)
181
182# The merge config lists should not attempt to extract items from both
183# builds for any of the following partitions. The partitions in
184# SINGLE_BUILD_PARTITIONS should come entirely from a single build (either
185# system or other, but not both).
186
187SINGLE_BUILD_PARTITIONS = (
188 'BOOT/',
189 'DATA/',
190 'ODM/',
191 'PRODUCT/',
192 'PRODUCT_SERVICES/',
193 'RADIO/',
194 'RECOVERY/',
195 'ROOT/',
196 'SYSTEM/',
197 'SYSTEM_OTHER/',
198 'VENDOR/',
199)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800200
201
Chris Grossfabf50a2019-05-02 12:42:09 -0700202def write_sorted_data(data, path):
203 """Write the sorted contents of either a list or dict to file.
204
205 This function sorts the contents of the list or dict and then
206 writes the resulting sorted contents to a file specified by path.
207
208 Args:
209 data: The list or dict to sort and write.
210 path: Path to the file to write the sorted values to. The file at path will
211 be overridden if it exists.
212 """
213 with open(path, 'w') as output:
214 sorted_data = sorted(data.keys()) if isinstance(data,
215 dict) else sorted(data)
216 for entry in sorted_data:
217 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):
223 """Extract items from target files to temporary directory.
224
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
240 with zipfile.ZipFile(
Daniel Normane5b134a2019-04-17 14:54:06 -0700241 target_files, 'r', allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800242 target_files_namelist = target_files_zipfile.namelist()
243
244 filtered_extract_item_list = []
245 for pattern in extract_item_list:
246 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
247 if not matching_namelist:
248 logger.warning('no match for %s', pattern)
249 else:
250 filtered_extract_item_list.append(pattern)
251
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800252 # Extract from target_files into target_files_temp_dir the
253 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800254
Daniel Normane5b134a2019-04-17 14:54:06 -0700255 common.UnzipToDir(target_files, target_files_temp_dir,
256 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800257
258
Daniel Normanfdb38812019-04-15 09:47:24 -0700259def copy_items(from_dir, to_dir, patterns):
260 """Similar to extract_items() except uses an input dir instead of zip."""
261 file_paths = []
262 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700263 file_paths.extend(
264 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
265 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700266
267 filtered_file_paths = set()
268 for pattern in patterns:
269 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
270
271 for file_path in filtered_file_paths:
272 original_file_path = os.path.join(from_dir, file_path)
273 copied_file_path = os.path.join(to_dir, file_path)
274 copied_file_dir = os.path.dirname(copied_file_path)
275 if not os.path.exists(copied_file_dir):
276 os.makedirs(copied_file_dir)
277 if os.path.islink(original_file_path):
278 os.symlink(os.readlink(original_file_path), copied_file_path)
279 else:
280 shutil.copyfile(original_file_path, copied_file_path)
281
282
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800283def read_config_list(config_file_path):
284 """Reads a config file into a list of strings.
285
286 Expects the file to be newline-separated.
287
288 Args:
289 config_file_path: The path to the config file to open and read.
Daniel Normane5b134a2019-04-17 14:54:06 -0700290
291 Returns:
292 The list of strings in the config file.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800293 """
294 with open(config_file_path) as config_file:
295 return config_file.read().splitlines()
296
297
Daniel Normane5b134a2019-04-17 14:54:06 -0700298def validate_config_lists(system_item_list, system_misc_info_keys,
299 other_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700300 """Performs validations on the merge config lists.
301
302 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700303 system_item_list: The list of items to extract from the partial system
304 target files package as is.
305 system_misc_info_keys: A list of keys to obtain from the system instance of
306 META/misc_info.txt. The remaining keys from the other instance.
307 other_item_list: The list of items to extract from the partial other target
308 files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700309
310 Returns:
311 False if a validation fails, otherwise true.
312 """
Daniel Normanedf12472019-05-22 10:47:08 -0700313 has_error = False
314
315 default_combined_item_set = set(DEFAULT_SYSTEM_ITEM_LIST)
316 default_combined_item_set.update(DEFAULT_OTHER_ITEM_LIST)
Daniel Normane5964522019-03-19 10:32:03 -0700317
318 combined_item_set = set(system_item_list)
319 combined_item_set.update(other_item_list)
320
321 # Check that the merge config lists are not missing any item specified
322 # by the default config lists.
323 difference = default_combined_item_set.difference(combined_item_set)
324 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700325 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700326 logger.error('Please ensure missing items are in either the '
327 'system-item-list or other-item-list files provided to '
328 'this script.')
Daniel Normanedf12472019-05-22 10:47:08 -0700329 has_error = True
330
331 for partition in SINGLE_BUILD_PARTITIONS:
332 in_system = any(item.startswith(partition) for item in system_item_list)
333 in_other = any(item.startswith(partition) for item in other_item_list)
334 if in_system and in_other:
335 logger.error(
336 'Cannot extract items from {0} for both the system and other builds. '
337 'Please ensure only one merge config item list includes {0}.'.format(
338 partition))
339 has_error = True
Daniel Normane5964522019-03-19 10:32:03 -0700340
Daniel Norman19b9fe92019-03-19 14:48:02 -0700341 if ('dynamic_partition_list' in system_misc_info_keys) or (
342 'super_partition_groups' in system_misc_info_keys):
343 logger.error('Dynamic partition misc info keys should come from '
344 'the other instance of META/misc_info.txt.')
Daniel Normanedf12472019-05-22 10:47:08 -0700345 has_error = True
Daniel Norman19b9fe92019-03-19 14:48:02 -0700346
Daniel Normanedf12472019-05-22 10:47:08 -0700347 return not has_error
Daniel Normane5964522019-03-19 10:32:03 -0700348
349
Daniel Normane5b134a2019-04-17 14:54:06 -0700350def process_ab_partitions_txt(system_target_files_temp_dir,
351 other_target_files_temp_dir,
352 output_target_files_temp_dir):
353 """Perform special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800354
355 This function merges the contents of the META/ab_partitions.txt files from
356 the system directory and the other directory, placing the merged result in
357 the output directory. The precondition in that the files are already
358 extracted. The post condition is that the output META/ab_partitions.txt
359 contains the merged content. The format for each ab_partitions.txt a one
360 partition name per line. The output file contains the union of the parition
361 names.
362
363 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700364 system_target_files_temp_dir: The name of a directory containing the special
365 items extracted from the system target files package.
366 other_target_files_temp_dir: The name of a directory containing the special
367 items extracted from the other target files package.
368 output_target_files_temp_dir: The name of a directory that will be used to
369 create the output target files package after all the special cases are
370 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800371 """
372
Daniel Normane5b134a2019-04-17 14:54:06 -0700373 system_ab_partitions_txt = os.path.join(system_target_files_temp_dir, 'META',
374 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800375
Daniel Normane5b134a2019-04-17 14:54:06 -0700376 other_ab_partitions_txt = os.path.join(other_target_files_temp_dir, 'META',
377 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800378
379 with open(system_ab_partitions_txt) as f:
380 system_ab_partitions = f.read().splitlines()
381
382 with open(other_ab_partitions_txt) as f:
383 other_ab_partitions = f.read().splitlines()
384
385 output_ab_partitions = set(system_ab_partitions + other_ab_partitions)
386
Daniel Normane5b134a2019-04-17 14:54:06 -0700387 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
388 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800389
Chris Grossfabf50a2019-05-02 12:42:09 -0700390 write_sorted_data(data=output_ab_partitions, path=output_ab_partitions_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800391
392
Bill Peckham364c1cc2019-03-29 18:27:23 -0700393def append_recovery_to_filesystem_config(output_target_files_temp_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700394 """Perform special processing for META/filesystem_config.txt.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700395
396 This function appends recovery information to META/filesystem_config.txt
397 so that recovery patch regeneration will succeed.
398
399 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700400 output_target_files_temp_dir: The name of a directory that will be used to
401 create the output target files package after all the special cases are
402 processed. We find filesystem_config.txt here.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700403 """
404
Daniel Normane5b134a2019-04-17 14:54:06 -0700405 filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
406 'filesystem_config.txt')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700407
408 with open(filesystem_config_txt, 'a') as f:
409 # TODO(bpeckham) this data is hard coded. It should be generated
410 # programmatically.
Daniel Normane5b134a2019-04-17 14:54:06 -0700411 f.write('system/bin/install-recovery.sh 0 0 750 '
412 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
413 f.write('system/recovery-from-boot.p 0 0 644 '
414 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
415 f.write('system/etc/recovery.img 0 0 440 '
416 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700417
418
Daniel Normana61cde02019-05-03 14:19:13 -0700419def merge_dynamic_partition_info_dicts(system_dict,
420 other_dict,
421 include_dynamic_partition_list=True,
422 size_prefix='',
423 size_suffix='',
424 list_prefix='',
425 list_suffix=''):
426 """Merges dynamic partition info variables.
427
428 Args:
429 system_dict: The dictionary of dynamic partition info variables from the
430 partial system target files.
431 other_dict: The dictionary of dynamic partition info variables from the
432 partial other target files.
433 include_dynamic_partition_list: If true, merges the dynamic_partition_list
434 variable. Not all use cases need this variable merged.
435 size_prefix: The prefix in partition group size variables that precedes the
436 name of the partition group. For example, partition group 'group_a' with
437 corresponding size variable 'super_group_a_group_size' would have the
438 size_prefix 'super_'.
439 size_suffix: Similar to size_prefix but for the variable's suffix. For
440 example, 'super_group_a_group_size' would have size_suffix '_group_size'.
441 list_prefix: Similar to size_prefix but for the partition group's
442 partition_list variable.
443 list_suffix: Similar to size_suffix but for the partition group's
444 partition_list variable.
445
446 Returns:
447 The merged dynamic partition info dictionary.
448 """
449 merged_dict = {}
450 # Partition groups and group sizes are defined by the other (non-system)
451 # dict because these values may vary for each board that uses a shared system
452 # image.
453 merged_dict['super_partition_groups'] = other_dict['super_partition_groups']
454 if include_dynamic_partition_list:
455 system_dynamic_partition_list = system_dict.get('dynamic_partition_list',
456 '')
457 other_dynamic_partition_list = other_dict.get('dynamic_partition_list', '')
458 merged_dict['dynamic_partition_list'] = (
459 '%s %s' %
460 (system_dynamic_partition_list, other_dynamic_partition_list)).strip()
461 for partition_group in merged_dict['super_partition_groups'].split(' '):
462 # Set the partition group's size using the value from the other dict.
463 key = '%s%s%s' % (size_prefix, partition_group, size_suffix)
464 if key not in other_dict:
465 raise ValueError('Other dict does not contain required key %s.' % key)
466 merged_dict[key] = other_dict[key]
467
468 # Set the partition group's partition list using a concatenation of the
469 # system and other partition lists.
470 key = '%s%s%s' % (list_prefix, partition_group, list_suffix)
471 merged_dict[key] = (
472 '%s %s' % (system_dict.get(key, ''), other_dict.get(key, ''))).strip()
473 return merged_dict
474
475
Daniel Normane5b134a2019-04-17 14:54:06 -0700476def process_misc_info_txt(system_target_files_temp_dir,
477 other_target_files_temp_dir,
478 output_target_files_temp_dir, system_misc_info_keys):
479 """Perform special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800480
481 This function merges the contents of the META/misc_info.txt files from the
482 system directory and the other directory, placing the merged result in the
483 output directory. The precondition in that the files are already extracted.
484 The post condition is that the output META/misc_info.txt contains the merged
485 content.
486
487 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700488 system_target_files_temp_dir: The name of a directory containing the special
489 items extracted from the system target files package.
490 other_target_files_temp_dir: The name of a directory containing the special
491 items extracted from the other target files package.
492 output_target_files_temp_dir: The name of a directory that will be used to
493 create the output target files package after all the special cases are
494 processed.
495 system_misc_info_keys: A list of keys to obtain from the system instance of
496 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800497 """
498
499 def read_helper(d):
500 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt')
501 with open(misc_info_txt) as f:
502 return list(f.read().splitlines())
503
504 system_info_dict = common.LoadDictionaryFromLines(
505 read_helper(system_target_files_temp_dir))
506
507 # We take most of the misc info from the other target files.
508
509 merged_info_dict = common.LoadDictionaryFromLines(
510 read_helper(other_target_files_temp_dir))
511
512 # Replace certain values in merged_info_dict with values from
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800513 # system_info_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800514
515 for key in system_misc_info_keys:
516 merged_info_dict[key] = system_info_dict[key]
517
Daniel Norman19b9fe92019-03-19 14:48:02 -0700518 # Merge misc info keys used for Dynamic Partitions.
519 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
520 system_info_dict.get('use_dynamic_partitions') == 'true'):
Daniel Normana61cde02019-05-03 14:19:13 -0700521 merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
522 system_dict=system_info_dict,
523 other_dict=merged_info_dict,
524 size_prefix='super_',
525 size_suffix='_group_size',
526 list_prefix='super_',
527 list_suffix='_partition_list')
528 merged_info_dict.update(merged_dynamic_partitions_dict)
Daniel Norman19b9fe92019-03-19 14:48:02 -0700529
Daniel Norman72c626f2019-05-13 15:58:14 -0700530 # Replace <image>_selinux_fc values with system or other file_contexts.bin
531 # depending on which dictionary the key came from.
532 # Only the file basename is required because all selinux_fc properties are
533 # replaced with the full path to the file under META/ when misc_info.txt is
534 # loaded from target files for repacking. See common.py LoadInfoDict().
535 for key in merged_info_dict:
536 if key.endswith('_selinux_fc'):
537 merged_info_dict[key] = 'other_file_contexts.bin'
538 for key in system_info_dict:
539 if key.endswith('_selinux_fc'):
540 merged_info_dict[key] = 'system_file_contexts.bin'
541
Daniel Normane5b134a2019-04-17 14:54:06 -0700542 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
543 'misc_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700544 write_sorted_data(data=merged_info_dict, path=output_misc_info_txt)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800545
546
Daniel Normana61cde02019-05-03 14:19:13 -0700547def process_dynamic_partitions_info_txt(system_target_files_dir,
548 other_target_files_dir,
549 output_target_files_dir):
550 """Perform special processing for META/dynamic_partitions_info.txt.
551
552 This function merges the contents of the META/dynamic_partitions_info.txt
553 files from the system directory and the other directory, placing the merged
554 result in the output directory.
555
556 This function does nothing if META/dynamic_partitions_info.txt from the other
557 directory does not exist.
558
559 Args:
560 system_target_files_dir: The name of a directory containing the special
561 items extracted from the system target files package.
562 other_target_files_dir: The name of a directory containing the special items
563 extracted from the other target files package.
564 output_target_files_dir: The name of a directory that will be used to create
565 the output target files package after all the special cases are processed.
566 """
567
568 if not os.path.exists(
569 os.path.join(other_target_files_dir, 'META',
570 'dynamic_partitions_info.txt')):
571 return
572
573 def read_helper(d):
574 dynamic_partitions_info_txt = os.path.join(d, 'META',
575 'dynamic_partitions_info.txt')
576 with open(dynamic_partitions_info_txt) as f:
577 return list(f.read().splitlines())
578
579 system_dynamic_partitions_dict = common.LoadDictionaryFromLines(
580 read_helper(system_target_files_dir))
581 other_dynamic_partitions_dict = common.LoadDictionaryFromLines(
582 read_helper(other_target_files_dir))
583
584 merged_dynamic_partitions_dict = merge_dynamic_partition_info_dicts(
585 system_dict=system_dynamic_partitions_dict,
586 other_dict=other_dynamic_partitions_dict,
587 # META/dynamic_partitions_info.txt does not use dynamic_partition_list.
588 include_dynamic_partition_list=False,
589 size_suffix='_size',
590 list_suffix='_partition_list')
591
592 output_dynamic_partitions_info_txt = os.path.join(
593 output_target_files_dir, 'META', 'dynamic_partitions_info.txt')
Chris Grossfabf50a2019-05-02 12:42:09 -0700594 write_sorted_data(
595 data=merged_dynamic_partitions_dict,
596 path=output_dynamic_partitions_info_txt)
597
598
599def process_apex_keys_apk_certs_common(system_target_files_dir,
600 other_target_files_dir,
601 output_target_files_dir, file_name):
602 """Perform special processing for META/apexkeys.txt or META/apkcerts.txt.
603
604 This function merges the contents of the META/apexkeys.txt or
605 META/apkcerts.txt
606 files from the system directory and the other directory, placing the merged
607 result in the output directory. The precondition in that the files are already
608 extracted.
609 The post condition is that the output META/apexkeys.txt or META/apkcerts.txt
610 contains the merged content.
611
612 Args:
613 system_target_files_dir: The name of a directory containing the special
614 items extracted from the system target files package.
615 other_target_files_dir: The name of a directory containing the special items
616 extracted from the other target files package.
617 output_target_files_dir: The name of a directory that will be used to create
618 the output target files package after all the special cases are processed.
619 file_name: The name of the file to merge. One of apkcerts.txt or
620 apexkeys.txt.
621 """
622
623 def read_helper(d):
624 temp = {}
625 file_path = os.path.join(d, 'META', file_name)
626 with open(file_path) as f:
627 for line in f:
628 if line.strip():
629 temp[line.split()[0]] = line.strip()
630 return temp
631
632 system_dict = read_helper(system_target_files_dir)
633 other_dict = read_helper(other_target_files_dir)
634
635 for key in system_dict:
636 if key in other_dict and other_dict[key] != system_dict[key]:
637 raise ValueError('Conflicting entries found in %s:\n %s and\n %s' %
638 (file_name, system_dict[key], other_dict[key]))
639 other_dict[key] = system_dict[key]
640
641 output_file = os.path.join(output_target_files_dir, 'META', file_name)
642
643 write_sorted_data(data=other_dict.values(), path=output_file)
Daniel Normana61cde02019-05-03 14:19:13 -0700644
645
Daniel Norman72c626f2019-05-13 15:58:14 -0700646def copy_file_contexts(system_target_files_dir, other_target_files_dir,
647 output_target_files_dir):
648 """Creates named copies of each build's file_contexts.bin in output META/."""
Daniel Normanedf12472019-05-22 10:47:08 -0700649 system_fc_path = os.path.join(system_target_files_dir, 'META',
650 'system_file_contexts.bin')
Daniel Norman72c626f2019-05-13 15:58:14 -0700651 if not os.path.exists(system_fc_path):
Daniel Normanedf12472019-05-22 10:47:08 -0700652 system_fc_path = os.path.join(system_target_files_dir, 'META',
653 'file_contexts.bin')
Daniel Norman72c626f2019-05-13 15:58:14 -0700654 if not os.path.exists(system_fc_path):
655 raise ValueError('Missing system file_contexts.bin.')
656 shutil.copyfile(
657 system_fc_path,
658 os.path.join(output_target_files_dir, 'META', 'system_file_contexts.bin'))
659
Daniel Normanedf12472019-05-22 10:47:08 -0700660 other_fc_path = os.path.join(other_target_files_dir, 'META',
661 'other_file_contexts.bin')
Daniel Norman72c626f2019-05-13 15:58:14 -0700662 if not os.path.exists(other_fc_path):
Daniel Normanedf12472019-05-22 10:47:08 -0700663 other_fc_path = os.path.join(other_target_files_dir, 'META',
664 'file_contexts.bin')
Daniel Norman72c626f2019-05-13 15:58:14 -0700665 if not os.path.exists(other_fc_path):
666 raise ValueError('Missing other file_contexts.bin.')
667 shutil.copyfile(
668 other_fc_path,
669 os.path.join(output_target_files_dir, 'META', 'other_file_contexts.bin'))
670
671
Bill Peckham736b2232019-05-06 12:50:55 -0700672def process_special_cases(system_target_files_temp_dir,
Daniel Normane5b134a2019-04-17 14:54:06 -0700673 other_target_files_temp_dir,
674 output_target_files_temp_dir, system_misc_info_keys,
675 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800676 """Perform special-case processing for certain target files items.
677
678 Certain files in the output target files package require special-case
679 processing. This function performs all that special-case processing.
680
681 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700682 system_target_files_temp_dir: The name of a directory containing the special
683 items extracted from the system target files package.
684 other_target_files_temp_dir: The name of a directory containing the special
685 items extracted from the other target files package.
686 output_target_files_temp_dir: The name of a directory that will be used to
687 create the output target files package after all the special cases are
688 processed.
689 system_misc_info_keys: A list of keys to obtain from the system instance of
690 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700691 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700692 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800693 """
694
Bill Peckham364c1cc2019-03-29 18:27:23 -0700695 if 'ab_update' in system_misc_info_keys:
696 process_ab_partitions_txt(
697 system_target_files_temp_dir=system_target_files_temp_dir,
698 other_target_files_temp_dir=other_target_files_temp_dir,
699 output_target_files_temp_dir=output_target_files_temp_dir)
700
701 if rebuild_recovery:
702 append_recovery_to_filesystem_config(
703 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800704
Daniel Norman72c626f2019-05-13 15:58:14 -0700705 copy_file_contexts(
706 system_target_files_dir=system_target_files_temp_dir,
707 other_target_files_dir=other_target_files_temp_dir,
708 output_target_files_dir=output_target_files_temp_dir)
709
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800710 process_misc_info_txt(
711 system_target_files_temp_dir=system_target_files_temp_dir,
712 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800713 output_target_files_temp_dir=output_target_files_temp_dir,
714 system_misc_info_keys=system_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800715
Daniel Normana61cde02019-05-03 14:19:13 -0700716 process_dynamic_partitions_info_txt(
Daniel Norman714bd122019-05-08 16:20:02 -0700717 system_target_files_dir=system_target_files_temp_dir,
718 other_target_files_dir=other_target_files_temp_dir,
719 output_target_files_dir=output_target_files_temp_dir)
Daniel Normana61cde02019-05-03 14:19:13 -0700720
Chris Grossfabf50a2019-05-02 12:42:09 -0700721 process_apex_keys_apk_certs_common(
722 system_target_files_dir=system_target_files_temp_dir,
723 other_target_files_dir=other_target_files_temp_dir,
724 output_target_files_dir=output_target_files_temp_dir,
725 file_name='apkcerts.txt')
726
727 process_apex_keys_apk_certs_common(
728 system_target_files_dir=system_target_files_temp_dir,
729 other_target_files_dir=other_target_files_temp_dir,
730 output_target_files_dir=output_target_files_temp_dir,
731 file_name='apexkeys.txt')
732
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800733
Daniel Normane5b134a2019-04-17 14:54:06 -0700734def merge_target_files(temp_dir, system_target_files, system_item_list,
735 system_misc_info_keys, other_target_files,
736 other_item_list, output_target_files, output_dir,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700737 output_item_list, output_ota, output_img,
738 output_super_empty, rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800739 """Merge two target files packages together.
740
741 This function takes system and other target files packages as input, performs
742 various file extractions, special case processing, and finally creates a
743 merged zip archive as output.
744
745 Args:
746 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700747 input target files packages, and also a scratch directory that we use for
748 temporary files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800749 system_target_files: The name of the zip archive containing the system
Daniel Normane5b134a2019-04-17 14:54:06 -0700750 partial target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800751 system_item_list: The list of items to extract from the partial system
Daniel Normane5b134a2019-04-17 14:54:06 -0700752 target files package as is, meaning these items will land in the output
753 target files package exactly as they appear in the input partial system
754 target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800755 system_misc_info_keys: The list of keys to obtain from the system instance
Daniel Normane5b134a2019-04-17 14:54:06 -0700756 of META/misc_info.txt. The remaining keys from the other instance.
757 other_target_files: The name of the zip archive containing the other partial
758 target files package.
759 other_item_list: The list of items to extract from the partial other target
760 files package as is, meaning these items will land in the output target
761 files package exactly as they appear in the input partial other target
762 files package.
763 output_target_files: The name of the output zip archive target files package
764 created by merging system and other.
765 output_dir: The destination directory for saving merged files.
766 output_item_list: The list of items to copy into the output_dir.
Daniel Norman3b64ce12019-04-16 16:11:35 -0700767 output_ota: The name of the output zip archive ota package.
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700768 output_img: The name of the output zip archive img package.
Daniel Normanf0318252019-04-15 11:34:56 -0700769 output_super_empty: If provided, creates a super_empty.img file from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700770 merged target files package and saves it at this path.
Daniel Normana4911da2019-03-15 14:36:21 -0700771 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700772 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800773 """
774
Daniel Normane5b134a2019-04-17 14:54:06 -0700775 logger.info('starting: merge system %s and other %s into output %s',
776 system_target_files, other_target_files, output_target_files)
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800777
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800778 # Create directory names that we'll use when we extract files from system,
779 # and other, and for zipping the final output.
780
781 system_target_files_temp_dir = os.path.join(temp_dir, 'system')
782 other_target_files_temp_dir = os.path.join(temp_dir, 'other')
783 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
784
785 # Extract "as is" items from the input system partial target files package.
786 # We extract them directly into the output temporary directory since the
787 # items do not need special case processing.
788
Bill Peckham889b0c62019-02-21 18:53:37 -0800789 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800790 target_files=system_target_files,
791 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800792 extract_item_list=system_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800793
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800794 # Extract "as is" items from the input other partial target files package. We
795 # extract them directly into the output temporary directory since the items
796 # do not need special case processing.
797
Bill Peckham889b0c62019-02-21 18:53:37 -0800798 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800799 target_files=other_target_files,
800 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800801 extract_item_list=other_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800802
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800803 # Extract "special" items from the input system partial target files package.
804 # We extract these items to different directory since they require special
805 # processing before they will end up in the output directory.
806
Bill Peckham889b0c62019-02-21 18:53:37 -0800807 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800808 target_files=system_target_files,
809 target_files_temp_dir=system_target_files_temp_dir,
Daniel Normanedf12472019-05-22 10:47:08 -0700810 extract_item_list=SYSTEM_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800811
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800812 # Extract "special" items from the input other partial target files package.
813 # We extract these items to different directory since they require special
814 # processing before they will end up in the output directory.
815
Bill Peckham889b0c62019-02-21 18:53:37 -0800816 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800817 target_files=other_target_files,
818 target_files_temp_dir=other_target_files_temp_dir,
Daniel Normanedf12472019-05-22 10:47:08 -0700819 extract_item_list=OTHER_EXTRACT_SPECIAL_ITEM_LIST)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800820
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800821 # Now that the temporary directories contain all the extracted files, perform
822 # special case processing on any items that need it. After this function
823 # completes successfully, all the files we need to create the output target
824 # files package are in place.
825
Bill Peckham889b0c62019-02-21 18:53:37 -0800826 process_special_cases(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800827 system_target_files_temp_dir=system_target_files_temp_dir,
828 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800829 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700830 system_misc_info_keys=system_misc_info_keys,
831 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800832
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800833 # Regenerate IMAGES in the temporary directory.
834
Daniel Normana4911da2019-03-15 14:36:21 -0700835 add_img_args = ['--verbose']
836 if rebuild_recovery:
837 add_img_args.append('--rebuild_recovery')
838 add_img_args.append(output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800839
840 add_img_to_target_files.main(add_img_args)
841
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700842 # Create super_empty.img using the merged misc_info.txt.
843
844 misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
845 'misc_info.txt')
846
847 def read_helper():
848 with open(misc_info_txt) as f:
849 return list(f.read().splitlines())
850
851 use_dynamic_partitions = common.LoadDictionaryFromLines(
852 read_helper()).get('use_dynamic_partitions')
853
854 if use_dynamic_partitions != 'true' and output_super_empty:
855 raise ValueError(
856 'Building super_empty.img requires use_dynamic_partitions=true.')
857 elif use_dynamic_partitions == 'true':
858 super_empty_img = os.path.join(output_target_files_temp_dir, 'IMAGES',
859 'super_empty.img')
860 build_super_image_args = [
861 misc_info_txt,
862 super_empty_img,
863 ]
864 build_super_image.main(build_super_image_args)
865
866 # Copy super_empty.img to the user-provided output_super_empty location.
867 if output_super_empty:
868 shutil.copyfile(super_empty_img, output_super_empty)
869
Daniel Normanb8a2f9d2019-04-24 12:55:51 -0700870 # Create the IMG package from the merged target files (before zipping, in
871 # order to avoid an unnecessary unzip and copy).
872
873 if output_img:
874 img_from_target_files_args = [
875 output_target_files_temp_dir,
876 output_img,
877 ]
878 img_from_target_files.main(img_from_target_files_args)
879
Daniel Normanfdb38812019-04-15 09:47:24 -0700880 # Finally, create the output target files zip archive and/or copy the
881 # output items to the output target files directory.
882
883 if output_dir:
884 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
885
886 if not output_target_files:
887 return
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800888
889 output_zip = os.path.abspath(output_target_files)
890 output_target_files_list = os.path.join(temp_dir, 'output.list')
Daniel Normane5b134a2019-04-17 14:54:06 -0700891 output_target_files_meta_dir = os.path.join(output_target_files_temp_dir,
892 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800893
Bill Peckham9662cfb2019-04-24 17:59:01 -0700894 find_command = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800895 'find',
896 output_target_files_meta_dir,
897 ]
Bill Peckham9662cfb2019-04-24 17:59:01 -0700898 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Normana61cde02019-05-03 14:19:13 -0700899 meta_content = common.RunAndCheckOutput(['sort'],
900 stdin=find_process.stdout,
Bill Peckham9662cfb2019-04-24 17:59:01 -0700901 verbose=False)
902
903 find_command = [
Daniel Normane5b134a2019-04-17 14:54:06 -0700904 'find', output_target_files_temp_dir, '-path',
905 output_target_files_meta_dir, '-prune', '-o', '-print'
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800906 ]
Bill Peckham9662cfb2019-04-24 17:59:01 -0700907 find_process = common.Run(find_command, stdout=subprocess.PIPE, verbose=False)
Daniel Normana61cde02019-05-03 14:19:13 -0700908 other_content = common.RunAndCheckOutput(['sort'],
909 stdin=find_process.stdout,
Bill Peckham9662cfb2019-04-24 17:59:01 -0700910 verbose=False)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800911
912 with open(output_target_files_list, 'wb') as f:
913 f.write(meta_content)
914 f.write(other_content)
915
916 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800917 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800918 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700919 '-o',
920 output_zip,
921 '-C',
922 output_target_files_temp_dir,
923 '-l',
924 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800925 ]
926 logger.info('creating %s', output_target_files)
Bill Peckham889b0c62019-02-21 18:53:37 -0800927 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800928
Daniel Norman3b64ce12019-04-16 16:11:35 -0700929 # Create the OTA package from the merged target files package.
930
931 if output_ota:
932 ota_from_target_files_args = [
933 output_zip,
934 output_ota,
935 ]
936 ota_from_target_files.main(ota_from_target_files_args)
937
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700938
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800939def call_func_with_temp_dir(func, keep_tmp):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800940 """Manage the creation and cleanup of the temporary directory.
941
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800942 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800943 directory. It also cleans up the temporary directory.
944
945 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700946 func: The function to call. Should accept one parameter, the path to the
947 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800948 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800949 """
950
951 # Create a temporary directory. This will serve as the parent of directories
952 # we use when we extract items from the input target files packages, and also
953 # a scratch directory that we use for temporary files.
954
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800955 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
956
957 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800958 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800959 except:
960 raise
961 finally:
962 if keep_tmp:
963 logger.info('keeping %s', temp_dir)
964 else:
965 common.Cleanup()
966
967
968def main():
969 """The main function.
970
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800971 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800972 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800973 """
974
975 common.InitLogging()
976
Bill Peckhamf753e152019-02-19 18:02:46 -0800977 def option_handler(o, a):
978 if o == '--system-target-files':
979 OPTIONS.system_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800980 elif o == '--system-item-list':
981 OPTIONS.system_item_list = a
982 elif o == '--system-misc-info-keys':
983 OPTIONS.system_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800984 elif o == '--other-target-files':
985 OPTIONS.other_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800986 elif o == '--other-item-list':
987 OPTIONS.other_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800988 elif o == '--output-target-files':
989 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700990 elif o == '--output-dir':
991 OPTIONS.output_dir = a
992 elif o == '--output-item-list':
993 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700994 elif o == '--output-ota':
995 OPTIONS.output_ota = a
Daniel Norman1bd2a1d2019-04-18 12:32:18 -0700996 elif o == '--output-img':
997 OPTIONS.output_img = a
Daniel Normanf0318252019-04-15 11:34:56 -0700998 elif o == '--output-super-empty':
999 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -07001000 elif o == '--rebuild_recovery':
1001 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -07001002 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -08001003 OPTIONS.keep_tmp = True
1004 else:
1005 return False
1006 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001007
Bill Peckhamf753e152019-02-19 18:02:46 -08001008 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -07001009 sys.argv[1:],
1010 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -08001011 extra_long_opts=[
1012 'system-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001013 'system-item-list=',
1014 'system-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001015 'other-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001016 'other-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -08001017 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -07001018 'output-dir=',
1019 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -07001020 'output-ota=',
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001021 'output-img=',
Daniel Normanf0318252019-04-15 11:34:56 -07001022 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -07001023 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -07001024 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -08001025 ],
1026 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001027
Daniel Normane5b134a2019-04-17 14:54:06 -07001028 if (args or OPTIONS.system_target_files is None or
1029 OPTIONS.other_target_files is None or
1030 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
1031 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -08001032 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -08001033 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001034
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001035 if OPTIONS.system_item_list:
1036 system_item_list = read_config_list(OPTIONS.system_item_list)
1037 else:
Daniel Normanedf12472019-05-22 10:47:08 -07001038 system_item_list = DEFAULT_SYSTEM_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001039
1040 if OPTIONS.system_misc_info_keys:
1041 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
1042 else:
Daniel Normanedf12472019-05-22 10:47:08 -07001043 system_misc_info_keys = DEFAULT_SYSTEM_MISC_INFO_KEYS
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001044
1045 if OPTIONS.other_item_list:
1046 other_item_list = read_config_list(OPTIONS.other_item_list)
1047 else:
Daniel Normanedf12472019-05-22 10:47:08 -07001048 other_item_list = DEFAULT_OTHER_ITEM_LIST
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001049
Daniel Normanfdb38812019-04-15 09:47:24 -07001050 if OPTIONS.output_item_list:
1051 output_item_list = read_config_list(OPTIONS.output_item_list)
1052 else:
1053 output_item_list = None
1054
Daniel Normane5964522019-03-19 10:32:03 -07001055 if not validate_config_lists(
1056 system_item_list=system_item_list,
Daniel Norman19b9fe92019-03-19 14:48:02 -07001057 system_misc_info_keys=system_misc_info_keys,
Daniel Normane5964522019-03-19 10:32:03 -07001058 other_item_list=other_item_list):
1059 sys.exit(1)
1060
Daniel Norman2c99c5b2019-03-07 13:01:48 -08001061 call_func_with_temp_dir(
1062 lambda temp_dir: merge_target_files(
1063 temp_dir=temp_dir,
1064 system_target_files=OPTIONS.system_target_files,
1065 system_item_list=system_item_list,
1066 system_misc_info_keys=system_misc_info_keys,
1067 other_target_files=OPTIONS.other_target_files,
1068 other_item_list=other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -07001069 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -07001070 output_dir=OPTIONS.output_dir,
1071 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -07001072 output_ota=OPTIONS.output_ota,
Daniel Norman1bd2a1d2019-04-18 12:32:18 -07001073 output_img=OPTIONS.output_img,
Daniel Normanf0318252019-04-15 11:34:56 -07001074 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -07001075 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -08001076
1077
1078if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -08001079 main()