blob: e306807798c6f7266c4602ff877ce2c968c03de1 [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
30 contents of default_system_item_list if provided.
31
32 --system-misc-info-keys system-misc-info-keys-file
33 The optional path to a newline-separated config file that replaces the
34 contents of default_system_misc_info_keys if provided.
35
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
42 contents of default_other_item_list if provided.
43
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 Normanf0318252019-04-15 11:34:56 -070061 --output-super-empty output-super-empty-image
62 If provided, creates a super_empty.img file from the merged target
63 files package and saves it at this path.
64
Daniel Normana4911da2019-03-15 14:36:21 -070065 --rebuild_recovery
66 Rebuild the recovery patch used by non-A/B devices and write it to the
67 system image.
Bill Peckham364c1cc2019-03-29 18:27:23 -070068
69 --keep-tmp
70 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080071"""
72
73from __future__ import print_function
74
Bill Peckhame9eb5f92019-02-01 15:52:10 -080075import fnmatch
76import logging
77import os
Daniel Normanfdb38812019-04-15 09:47:24 -070078import shutil
Bill Peckhame9eb5f92019-02-01 15:52:10 -080079import sys
80import zipfile
81
Bill Peckhame9eb5f92019-02-01 15:52:10 -080082import add_img_to_target_files
Daniel Normanf0318252019-04-15 11:34:56 -070083import build_super_image
84import common
Daniel Norman3b64ce12019-04-16 16:11:35 -070085import ota_from_target_files
Bill Peckhame9eb5f92019-02-01 15:52:10 -080086
87logger = logging.getLogger(__name__)
88OPTIONS = common.OPTIONS
89OPTIONS.verbose = True
Bill Peckhamf753e152019-02-19 18:02:46 -080090OPTIONS.system_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080091OPTIONS.system_item_list = None
92OPTIONS.system_misc_info_keys = None
Bill Peckhamf753e152019-02-19 18:02:46 -080093OPTIONS.other_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080094OPTIONS.other_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -080095OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -070096OPTIONS.output_dir = None
97OPTIONS.output_item_list = None
Daniel Norman3b64ce12019-04-16 16:11:35 -070098OPTIONS.output_ota = None
Daniel Normanf0318252019-04-15 11:34:56 -070099OPTIONS.output_super_empty = None
Daniel Normana4911da2019-03-15 14:36:21 -0700100OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -0800101OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800102
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800103# default_system_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800104# system target files package as is, meaning these items will land in the
105# output target files package exactly as they appear in the input partial
106# system target files package.
107
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800108default_system_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800109 'META/apkcerts.txt',
110 'META/filesystem_config.txt',
111 'META/root_filesystem_config.txt',
112 'META/system_manifest.xml',
113 'META/system_matrix.xml',
114 'META/update_engine_config.txt',
115 'PRODUCT/*',
116 'ROOT/*',
117 'SYSTEM/*',
118]
119
120# system_extract_special_item_list is a list of items to extract from the
121# partial system target files package that need some special processing, such
122# as some sort of combination with items from the partial other target files
123# package.
124
125system_extract_special_item_list = [
126 'META/*',
127]
128
Daniel Normane5b134a2019-04-17 14:54:06 -0700129# default_system_misc_info_keys is a list of keys to obtain from the system
130# instance of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800131
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800132default_system_misc_info_keys = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800133 'avb_system_hashtree_enable',
134 'avb_system_add_hashtree_footer_args',
135 'avb_system_key_path',
136 'avb_system_algorithm',
137 'avb_system_rollback_index_location',
138 'avb_product_hashtree_enable',
139 'avb_product_add_hashtree_footer_args',
140 'avb_product_services_hashtree_enable',
141 'avb_product_services_add_hashtree_footer_args',
142 'system_root_image',
143 'root_dir',
144 'ab_update',
145 'default_system_dev_certificate',
146 'system_size',
147]
148
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800149# default_other_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800150# other target files package as is, meaning these items will land in the output
151# target files package exactly as they appear in the input partial other target
152# files package.
153
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800154default_other_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800155 'META/boot_filesystem_config.txt',
156 'META/otakeys.txt',
157 'META/releasetools.py',
158 'META/vendor_filesystem_config.txt',
159 'META/vendor_manifest.xml',
160 'META/vendor_matrix.xml',
161 'BOOT/*',
162 'DATA/*',
163 'ODM/*',
164 'OTA/android-info.txt',
165 'PREBUILT_IMAGES/*',
166 'RADIO/*',
167 'VENDOR/*',
168]
169
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800170# other_extract_special_item_list is a list of items to extract from the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800171# partial other target files package that need some special processing, such as
172# some sort of combination with items from the partial system target files
173# package.
174
175other_extract_special_item_list = [
176 'META/*',
177]
178
179
180def extract_items(target_files, target_files_temp_dir, extract_item_list):
181 """Extract items from target files to temporary directory.
182
183 This function extracts from the specified target files zip archive into the
184 specified temporary directory, the items specified in the extract item list.
185
186 Args:
187 target_files: The target files zip archive from which to extract items.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800188 target_files_temp_dir: The temporary directory where the extracted items
Daniel Normane5b134a2019-04-17 14:54:06 -0700189 will land.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800190 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800191 """
192
193 logger.info('extracting from %s', target_files)
194
195 # Filter the extract_item_list to remove any items that do not exist in the
196 # zip file. Otherwise, the extraction step will fail.
197
198 with zipfile.ZipFile(
Daniel Normane5b134a2019-04-17 14:54:06 -0700199 target_files, 'r', allowZip64=True) as target_files_zipfile:
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800200 target_files_namelist = target_files_zipfile.namelist()
201
202 filtered_extract_item_list = []
203 for pattern in extract_item_list:
204 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
205 if not matching_namelist:
206 logger.warning('no match for %s', pattern)
207 else:
208 filtered_extract_item_list.append(pattern)
209
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800210 # Extract from target_files into target_files_temp_dir the
211 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800212
Daniel Normane5b134a2019-04-17 14:54:06 -0700213 common.UnzipToDir(target_files, target_files_temp_dir,
214 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800215
216
Daniel Normanfdb38812019-04-15 09:47:24 -0700217def copy_items(from_dir, to_dir, patterns):
218 """Similar to extract_items() except uses an input dir instead of zip."""
219 file_paths = []
220 for dirpath, _, filenames in os.walk(from_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700221 file_paths.extend(
222 os.path.relpath(path=os.path.join(dirpath, filename), start=from_dir)
223 for filename in filenames)
Daniel Normanfdb38812019-04-15 09:47:24 -0700224
225 filtered_file_paths = set()
226 for pattern in patterns:
227 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
228
229 for file_path in filtered_file_paths:
230 original_file_path = os.path.join(from_dir, file_path)
231 copied_file_path = os.path.join(to_dir, file_path)
232 copied_file_dir = os.path.dirname(copied_file_path)
233 if not os.path.exists(copied_file_dir):
234 os.makedirs(copied_file_dir)
235 if os.path.islink(original_file_path):
236 os.symlink(os.readlink(original_file_path), copied_file_path)
237 else:
238 shutil.copyfile(original_file_path, copied_file_path)
239
240
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800241def read_config_list(config_file_path):
242 """Reads a config file into a list of strings.
243
244 Expects the file to be newline-separated.
245
246 Args:
247 config_file_path: The path to the config file to open and read.
Daniel Normane5b134a2019-04-17 14:54:06 -0700248
249 Returns:
250 The list of strings in the config file.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800251 """
252 with open(config_file_path) as config_file:
253 return config_file.read().splitlines()
254
255
Daniel Normane5b134a2019-04-17 14:54:06 -0700256def validate_config_lists(system_item_list, system_misc_info_keys,
257 other_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700258 """Performs validations on the merge config lists.
259
260 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700261 system_item_list: The list of items to extract from the partial system
262 target files package as is.
263 system_misc_info_keys: A list of keys to obtain from the system instance of
264 META/misc_info.txt. The remaining keys from the other instance.
265 other_item_list: The list of items to extract from the partial other target
266 files package as is.
Daniel Normane5964522019-03-19 10:32:03 -0700267
268 Returns:
269 False if a validation fails, otherwise true.
270 """
271 default_combined_item_set = set(default_system_item_list)
272 default_combined_item_set.update(default_other_item_list)
273
274 combined_item_set = set(system_item_list)
275 combined_item_set.update(other_item_list)
276
277 # Check that the merge config lists are not missing any item specified
278 # by the default config lists.
279 difference = default_combined_item_set.difference(combined_item_set)
280 if difference:
Daniel Normane5b134a2019-04-17 14:54:06 -0700281 logger.error('Missing merge config items: %s', list(difference))
Daniel Normane5964522019-03-19 10:32:03 -0700282 logger.error('Please ensure missing items are in either the '
283 'system-item-list or other-item-list files provided to '
284 'this script.')
285 return False
286
Daniel Norman19b9fe92019-03-19 14:48:02 -0700287 if ('dynamic_partition_list' in system_misc_info_keys) or (
288 'super_partition_groups' in system_misc_info_keys):
289 logger.error('Dynamic partition misc info keys should come from '
290 'the other instance of META/misc_info.txt.')
291 return False
292
Daniel Normane5964522019-03-19 10:32:03 -0700293 return True
294
295
Daniel Normane5b134a2019-04-17 14:54:06 -0700296def process_ab_partitions_txt(system_target_files_temp_dir,
297 other_target_files_temp_dir,
298 output_target_files_temp_dir):
299 """Perform special processing for META/ab_partitions.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800300
301 This function merges the contents of the META/ab_partitions.txt files from
302 the system directory and the other directory, placing the merged result in
303 the output directory. The precondition in that the files are already
304 extracted. The post condition is that the output META/ab_partitions.txt
305 contains the merged content. The format for each ab_partitions.txt a one
306 partition name per line. The output file contains the union of the parition
307 names.
308
309 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700310 system_target_files_temp_dir: The name of a directory containing the special
311 items extracted from the system target files package.
312 other_target_files_temp_dir: The name of a directory containing the special
313 items extracted from the other target files package.
314 output_target_files_temp_dir: The name of a directory that will be used to
315 create the output target files package after all the special cases are
316 processed.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800317 """
318
Daniel Normane5b134a2019-04-17 14:54:06 -0700319 system_ab_partitions_txt = os.path.join(system_target_files_temp_dir, 'META',
320 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800321
Daniel Normane5b134a2019-04-17 14:54:06 -0700322 other_ab_partitions_txt = os.path.join(other_target_files_temp_dir, 'META',
323 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800324
325 with open(system_ab_partitions_txt) as f:
326 system_ab_partitions = f.read().splitlines()
327
328 with open(other_ab_partitions_txt) as f:
329 other_ab_partitions = f.read().splitlines()
330
331 output_ab_partitions = set(system_ab_partitions + other_ab_partitions)
332
Daniel Normane5b134a2019-04-17 14:54:06 -0700333 output_ab_partitions_txt = os.path.join(output_target_files_temp_dir, 'META',
334 'ab_partitions.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800335
336 with open(output_ab_partitions_txt, 'w') as output:
337 for partition in sorted(output_ab_partitions):
338 output.write('%s\n' % partition)
339
340
Bill Peckham364c1cc2019-03-29 18:27:23 -0700341def append_recovery_to_filesystem_config(output_target_files_temp_dir):
Daniel Normane5b134a2019-04-17 14:54:06 -0700342 """Perform special processing for META/filesystem_config.txt.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700343
344 This function appends recovery information to META/filesystem_config.txt
345 so that recovery patch regeneration will succeed.
346
347 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700348 output_target_files_temp_dir: The name of a directory that will be used to
349 create the output target files package after all the special cases are
350 processed. We find filesystem_config.txt here.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700351 """
352
Daniel Normane5b134a2019-04-17 14:54:06 -0700353 filesystem_config_txt = os.path.join(output_target_files_temp_dir, 'META',
354 'filesystem_config.txt')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700355
356 with open(filesystem_config_txt, 'a') as f:
357 # TODO(bpeckham) this data is hard coded. It should be generated
358 # programmatically.
Daniel Normane5b134a2019-04-17 14:54:06 -0700359 f.write('system/bin/install-recovery.sh 0 0 750 '
360 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
361 f.write('system/recovery-from-boot.p 0 0 644 '
362 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
363 f.write('system/etc/recovery.img 0 0 440 '
364 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
Bill Peckham364c1cc2019-03-29 18:27:23 -0700365
366
Daniel Normane5b134a2019-04-17 14:54:06 -0700367def process_misc_info_txt(system_target_files_temp_dir,
368 other_target_files_temp_dir,
369 output_target_files_temp_dir, system_misc_info_keys):
370 """Perform special processing for META/misc_info.txt.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800371
372 This function merges the contents of the META/misc_info.txt files from the
373 system directory and the other directory, placing the merged result in the
374 output directory. The precondition in that the files are already extracted.
375 The post condition is that the output META/misc_info.txt contains the merged
376 content.
377
378 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700379 system_target_files_temp_dir: The name of a directory containing the special
380 items extracted from the system target files package.
381 other_target_files_temp_dir: The name of a directory containing the special
382 items extracted from the other target files package.
383 output_target_files_temp_dir: The name of a directory that will be used to
384 create the output target files package after all the special cases are
385 processed.
386 system_misc_info_keys: A list of keys to obtain from the system instance of
387 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800388 """
389
390 def read_helper(d):
391 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt')
392 with open(misc_info_txt) as f:
393 return list(f.read().splitlines())
394
395 system_info_dict = common.LoadDictionaryFromLines(
396 read_helper(system_target_files_temp_dir))
397
398 # We take most of the misc info from the other target files.
399
400 merged_info_dict = common.LoadDictionaryFromLines(
401 read_helper(other_target_files_temp_dir))
402
403 # Replace certain values in merged_info_dict with values from
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800404 # system_info_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800405
406 for key in system_misc_info_keys:
407 merged_info_dict[key] = system_info_dict[key]
408
Daniel Norman19b9fe92019-03-19 14:48:02 -0700409 # Merge misc info keys used for Dynamic Partitions.
410 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
411 system_info_dict.get('use_dynamic_partitions') == 'true'):
412 merged_info_dict['dynamic_partition_list'] = '%s %s' % (
413 system_info_dict.get('dynamic_partition_list', ''),
414 merged_info_dict.get('dynamic_partition_list', ''))
415 # Partition groups and group sizes are defined by the other (non-system)
416 # misc info file because these values may vary for each board that uses
417 # a shared system image.
Daniel Normane5b134a2019-04-17 14:54:06 -0700418 for partition_group in merged_info_dict['super_partition_groups'].split(
419 ' '):
Daniel Norman19b9fe92019-03-19 14:48:02 -0700420 if ('super_%s_group_size' % partition_group) not in merged_info_dict:
Daniel Normanf0318252019-04-15 11:34:56 -0700421 raise ValueError(
Daniel Norman19b9fe92019-03-19 14:48:02 -0700422 'Other META/misc_info.txt does not contain required key '
423 'super_%s_group_size.' % partition_group)
424 key = 'super_%s_partition_list' % partition_group
Daniel Normane5b134a2019-04-17 14:54:06 -0700425 merged_info_dict[key] = '%s %s' % (system_info_dict.get(
426 key, ''), merged_info_dict.get(key, ''))
Daniel Norman19b9fe92019-03-19 14:48:02 -0700427
Daniel Normane5b134a2019-04-17 14:54:06 -0700428 output_misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
429 'misc_info.txt')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800430
431 sorted_keys = sorted(merged_info_dict.keys())
432
433 with open(output_misc_info_txt, 'w') as output:
434 for key in sorted_keys:
435 output.write('{}={}\n'.format(key, merged_info_dict[key]))
436
437
438def process_file_contexts_bin(temp_dir, output_target_files_temp_dir):
439 """Perform special processing for META/file_contexts.bin.
440
441 This function combines plat_file_contexts and vendor_file_contexts, which are
442 expected to already be extracted in temp_dir, to produce a merged
443 file_contexts.bin that will land in temp_dir at META/file_contexts.bin.
444
445 Args:
446 temp_dir: The name of a scratch directory that this function can use for
Daniel Normane5b134a2019-04-17 14:54:06 -0700447 intermediate files generated during processing.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800448 output_target_files_temp_dir: The name of the working directory that must
Daniel Normane5b134a2019-04-17 14:54:06 -0700449 already contain plat_file_contexts and vendor_file_contexts (in the
450 appropriate sub directories), and to which META/file_contexts.bin will be
451 written.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800452 """
453
454 # To create a merged file_contexts.bin file, we use the system and vendor
455 # file contexts files as input, the m4 tool to combine them, the sorting tool
456 # to sort, and finally the sefcontext_compile tool to generate the final
457 # output. We currently omit a checkfc step since the files had been checked
458 # as part of the build.
459
460 # The m4 step concatenates the two input files contexts files. Since m4
461 # writes to stdout, we receive that into an array of bytes, and then write it
462 # to a file.
463
464 # Collect the file contexts that we're going to combine from SYSTEM, VENDOR,
465 # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional.
466
467 file_contexts_list = []
468
469 for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']:
470 prefix = 'plat' if partition == 'SYSTEM' else partition.lower()
471
Daniel Normane5b134a2019-04-17 14:54:06 -0700472 file_contexts = os.path.join(output_target_files_temp_dir, partition, 'etc',
473 'selinux', prefix + '_file_contexts')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800474
475 mandatory = partition in ['SYSTEM', 'VENDOR']
476
477 if mandatory or os.path.isfile(file_contexts):
478 file_contexts_list.append(file_contexts)
479 else:
480 logger.warning('file not found: %s', file_contexts)
481
482 command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list
483
484 merged_content = common.RunAndCheckOutput(command, verbose=False)
485
486 merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt')
487
488 with open(merged_file_contexts_txt, 'wb') as f:
489 f.write(merged_content)
490
491 # The sort step sorts the concatenated file.
492
493 sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt')
494 command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt]
Bill Peckham889b0c62019-02-21 18:53:37 -0800495 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800496
497 # Finally, the compile step creates the final META/file_contexts.bin.
498
Daniel Normane5b134a2019-04-17 14:54:06 -0700499 file_contexts_bin = os.path.join(output_target_files_temp_dir, 'META',
500 'file_contexts.bin')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800501
502 command = [
503 'sefcontext_compile',
Daniel Normane5b134a2019-04-17 14:54:06 -0700504 '-o',
505 file_contexts_bin,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800506 sorted_file_contexts_txt,
507 ]
508
Bill Peckham889b0c62019-02-21 18:53:37 -0800509 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800510
511
Daniel Normane5b134a2019-04-17 14:54:06 -0700512def process_special_cases(temp_dir, system_target_files_temp_dir,
513 other_target_files_temp_dir,
514 output_target_files_temp_dir, system_misc_info_keys,
515 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800516 """Perform special-case processing for certain target files items.
517
518 Certain files in the output target files package require special-case
519 processing. This function performs all that special-case processing.
520
521 Args:
522 temp_dir: The name of a scratch directory that this function can use for
Daniel Normane5b134a2019-04-17 14:54:06 -0700523 intermediate files generated during processing.
524 system_target_files_temp_dir: The name of a directory containing the special
525 items extracted from the system target files package.
526 other_target_files_temp_dir: The name of a directory containing the special
527 items extracted from the other target files package.
528 output_target_files_temp_dir: The name of a directory that will be used to
529 create the output target files package after all the special cases are
530 processed.
531 system_misc_info_keys: A list of keys to obtain from the system instance of
532 META/misc_info.txt. The remaining keys from the other instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700533 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700534 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800535 """
536
Bill Peckham364c1cc2019-03-29 18:27:23 -0700537 if 'ab_update' in system_misc_info_keys:
538 process_ab_partitions_txt(
539 system_target_files_temp_dir=system_target_files_temp_dir,
540 other_target_files_temp_dir=other_target_files_temp_dir,
541 output_target_files_temp_dir=output_target_files_temp_dir)
542
543 if rebuild_recovery:
544 append_recovery_to_filesystem_config(
545 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800546
547 process_misc_info_txt(
548 system_target_files_temp_dir=system_target_files_temp_dir,
549 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800550 output_target_files_temp_dir=output_target_files_temp_dir,
551 system_misc_info_keys=system_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800552
Bill Peckham889b0c62019-02-21 18:53:37 -0800553 process_file_contexts_bin(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800554 temp_dir=temp_dir,
555 output_target_files_temp_dir=output_target_files_temp_dir)
556
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800557
Daniel Normane5b134a2019-04-17 14:54:06 -0700558def merge_target_files(temp_dir, system_target_files, system_item_list,
559 system_misc_info_keys, other_target_files,
560 other_item_list, output_target_files, output_dir,
561 output_item_list, output_ota, output_super_empty,
562 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800563 """Merge two target files packages together.
564
565 This function takes system and other target files packages as input, performs
566 various file extractions, special case processing, and finally creates a
567 merged zip archive as output.
568
569 Args:
570 temp_dir: The name of a directory we use when we extract items from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700571 input target files packages, and also a scratch directory that we use for
572 temporary files.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800573 system_target_files: The name of the zip archive containing the system
Daniel Normane5b134a2019-04-17 14:54:06 -0700574 partial target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800575 system_item_list: The list of items to extract from the partial system
Daniel Normane5b134a2019-04-17 14:54:06 -0700576 target files package as is, meaning these items will land in the output
577 target files package exactly as they appear in the input partial system
578 target files package.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800579 system_misc_info_keys: The list of keys to obtain from the system instance
Daniel Normane5b134a2019-04-17 14:54:06 -0700580 of META/misc_info.txt. The remaining keys from the other instance.
581 other_target_files: The name of the zip archive containing the other partial
582 target files package.
583 other_item_list: The list of items to extract from the partial other target
584 files package as is, meaning these items will land in the output target
585 files package exactly as they appear in the input partial other target
586 files package.
587 output_target_files: The name of the output zip archive target files package
588 created by merging system and other.
589 output_dir: The destination directory for saving merged files.
590 output_item_list: The list of items to copy into the output_dir.
Daniel Norman3b64ce12019-04-16 16:11:35 -0700591 output_ota: The name of the output zip archive ota package.
Daniel Normanf0318252019-04-15 11:34:56 -0700592 output_super_empty: If provided, creates a super_empty.img file from the
Daniel Normane5b134a2019-04-17 14:54:06 -0700593 merged target files package and saves it at this path.
Daniel Normana4911da2019-03-15 14:36:21 -0700594 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
Daniel Normane5b134a2019-04-17 14:54:06 -0700595 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800596 """
597
Daniel Normane5b134a2019-04-17 14:54:06 -0700598 logger.info('starting: merge system %s and other %s into output %s',
599 system_target_files, other_target_files, output_target_files)
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800600
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800601 # Create directory names that we'll use when we extract files from system,
602 # and other, and for zipping the final output.
603
604 system_target_files_temp_dir = os.path.join(temp_dir, 'system')
605 other_target_files_temp_dir = os.path.join(temp_dir, 'other')
606 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
607
608 # Extract "as is" items from the input system partial target files package.
609 # We extract them directly into the output temporary directory since the
610 # items do not need special case processing.
611
Bill Peckham889b0c62019-02-21 18:53:37 -0800612 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800613 target_files=system_target_files,
614 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800615 extract_item_list=system_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800616
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800617 # Extract "as is" items from the input other partial target files package. We
618 # extract them directly into the output temporary directory since the items
619 # do not need special case processing.
620
Bill Peckham889b0c62019-02-21 18:53:37 -0800621 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800622 target_files=other_target_files,
623 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800624 extract_item_list=other_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800625
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800626 # Extract "special" items from the input system partial target files package.
627 # We extract these items to different directory since they require special
628 # processing before they will end up in the output directory.
629
Bill Peckham889b0c62019-02-21 18:53:37 -0800630 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800631 target_files=system_target_files,
632 target_files_temp_dir=system_target_files_temp_dir,
633 extract_item_list=system_extract_special_item_list)
634
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800635 # Extract "special" items from the input other partial target files package.
636 # We extract these items to different directory since they require special
637 # processing before they will end up in the output directory.
638
Bill Peckham889b0c62019-02-21 18:53:37 -0800639 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800640 target_files=other_target_files,
641 target_files_temp_dir=other_target_files_temp_dir,
642 extract_item_list=other_extract_special_item_list)
643
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800644 # Now that the temporary directories contain all the extracted files, perform
645 # special case processing on any items that need it. After this function
646 # completes successfully, all the files we need to create the output target
647 # files package are in place.
648
Bill Peckham889b0c62019-02-21 18:53:37 -0800649 process_special_cases(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800650 temp_dir=temp_dir,
651 system_target_files_temp_dir=system_target_files_temp_dir,
652 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800653 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700654 system_misc_info_keys=system_misc_info_keys,
655 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800656
Daniel Normanf0318252019-04-15 11:34:56 -0700657 # Create super_empty.img using the merged misc_info.txt.
658
659 if output_super_empty:
Daniel Normane5b134a2019-04-17 14:54:06 -0700660 misc_info_txt = os.path.join(output_target_files_temp_dir, 'META',
661 'misc_info.txt')
662
Daniel Normanf0318252019-04-15 11:34:56 -0700663 def read_helper():
664 with open(misc_info_txt) as f:
665 return list(f.read().splitlines())
666
667 misc_info_dict = common.LoadDictionaryFromLines(read_helper())
668 if misc_info_dict.get('use_dynamic_partitions') != 'true':
669 raise ValueError(
670 'Building super_empty.img requires use_dynamic_partitions=true.')
671
672 build_super_image_args = [
Daniel Normane5b134a2019-04-17 14:54:06 -0700673 '--verbose',
674 misc_info_txt,
675 output_super_empty,
Daniel Normanf0318252019-04-15 11:34:56 -0700676 ]
677 build_super_image.main(build_super_image_args)
678
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800679 # Regenerate IMAGES in the temporary directory.
680
Daniel Normana4911da2019-03-15 14:36:21 -0700681 add_img_args = ['--verbose']
682 if rebuild_recovery:
683 add_img_args.append('--rebuild_recovery')
684 add_img_args.append(output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800685
686 add_img_to_target_files.main(add_img_args)
687
Daniel Normanfdb38812019-04-15 09:47:24 -0700688 # Finally, create the output target files zip archive and/or copy the
689 # output items to the output target files directory.
690
691 if output_dir:
692 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
693
694 if not output_target_files:
695 return
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800696
697 output_zip = os.path.abspath(output_target_files)
698 output_target_files_list = os.path.join(temp_dir, 'output.list')
Daniel Normane5b134a2019-04-17 14:54:06 -0700699 output_target_files_meta_dir = os.path.join(output_target_files_temp_dir,
700 'META')
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800701
702 command = [
703 'find',
704 output_target_files_meta_dir,
705 ]
706 # TODO(bpeckham): sort this to be more like build.
707 meta_content = common.RunAndCheckOutput(command, verbose=False)
708 command = [
Daniel Normane5b134a2019-04-17 14:54:06 -0700709 'find', output_target_files_temp_dir, '-path',
710 output_target_files_meta_dir, '-prune', '-o', '-print'
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800711 ]
712 # TODO(bpeckham): sort this to be more like build.
713 other_content = common.RunAndCheckOutput(command, verbose=False)
714
715 with open(output_target_files_list, 'wb') as f:
716 f.write(meta_content)
717 f.write(other_content)
718
719 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800720 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800721 '-d',
Daniel Normane5b134a2019-04-17 14:54:06 -0700722 '-o',
723 output_zip,
724 '-C',
725 output_target_files_temp_dir,
726 '-l',
727 output_target_files_list,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800728 ]
729 logger.info('creating %s', output_target_files)
Bill Peckham889b0c62019-02-21 18:53:37 -0800730 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800731
Daniel Norman3b64ce12019-04-16 16:11:35 -0700732 # Create the OTA package from the merged target files package.
733
734 if output_ota:
735 ota_from_target_files_args = [
736 output_zip,
737 output_ota,
738 ]
739 ota_from_target_files.main(ota_from_target_files_args)
740
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800741
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800742def call_func_with_temp_dir(func, keep_tmp):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800743 """Manage the creation and cleanup of the temporary directory.
744
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800745 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800746 directory. It also cleans up the temporary directory.
747
748 Args:
Daniel Normane5b134a2019-04-17 14:54:06 -0700749 func: The function to call. Should accept one parameter, the path to the
750 temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800751 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800752 """
753
754 # Create a temporary directory. This will serve as the parent of directories
755 # we use when we extract items from the input target files packages, and also
756 # a scratch directory that we use for temporary files.
757
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800758 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
759
760 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800761 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800762 except:
763 raise
764 finally:
765 if keep_tmp:
766 logger.info('keeping %s', temp_dir)
767 else:
768 common.Cleanup()
769
770
771def main():
772 """The main function.
773
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800774 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800775 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800776 """
777
778 common.InitLogging()
779
Bill Peckhamf753e152019-02-19 18:02:46 -0800780 def option_handler(o, a):
781 if o == '--system-target-files':
782 OPTIONS.system_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800783 elif o == '--system-item-list':
784 OPTIONS.system_item_list = a
785 elif o == '--system-misc-info-keys':
786 OPTIONS.system_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800787 elif o == '--other-target-files':
788 OPTIONS.other_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800789 elif o == '--other-item-list':
790 OPTIONS.other_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800791 elif o == '--output-target-files':
792 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700793 elif o == '--output-dir':
794 OPTIONS.output_dir = a
795 elif o == '--output-item-list':
796 OPTIONS.output_item_list = a
Daniel Norman3b64ce12019-04-16 16:11:35 -0700797 elif o == '--output-ota':
798 OPTIONS.output_ota = a
Daniel Normanf0318252019-04-15 11:34:56 -0700799 elif o == '--output-super-empty':
800 OPTIONS.output_super_empty = a
Daniel Normana4911da2019-03-15 14:36:21 -0700801 elif o == '--rebuild_recovery':
802 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700803 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800804 OPTIONS.keep_tmp = True
805 else:
806 return False
807 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800808
Bill Peckhamf753e152019-02-19 18:02:46 -0800809 args = common.ParseOptions(
Daniel Normane5b134a2019-04-17 14:54:06 -0700810 sys.argv[1:],
811 __doc__,
Bill Peckhamf753e152019-02-19 18:02:46 -0800812 extra_long_opts=[
813 'system-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800814 'system-item-list=',
815 'system-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800816 'other-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800817 'other-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800818 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -0700819 'output-dir=',
820 'output-item-list=',
Daniel Norman3b64ce12019-04-16 16:11:35 -0700821 'output-ota=',
Daniel Normanf0318252019-04-15 11:34:56 -0700822 'output-super-empty=',
Daniel Normana4911da2019-03-15 14:36:21 -0700823 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -0700824 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -0800825 ],
826 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800827
Daniel Normane5b134a2019-04-17 14:54:06 -0700828 if (args or OPTIONS.system_target_files is None or
829 OPTIONS.other_target_files is None or
830 (OPTIONS.output_target_files is None and OPTIONS.output_dir is None) or
831 (OPTIONS.output_dir is not None and OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -0800832 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -0800833 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800834
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800835 if OPTIONS.system_item_list:
836 system_item_list = read_config_list(OPTIONS.system_item_list)
837 else:
838 system_item_list = default_system_item_list
839
840 if OPTIONS.system_misc_info_keys:
841 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
842 else:
843 system_misc_info_keys = default_system_misc_info_keys
844
845 if OPTIONS.other_item_list:
846 other_item_list = read_config_list(OPTIONS.other_item_list)
847 else:
848 other_item_list = default_other_item_list
849
Daniel Normanfdb38812019-04-15 09:47:24 -0700850 if OPTIONS.output_item_list:
851 output_item_list = read_config_list(OPTIONS.output_item_list)
852 else:
853 output_item_list = None
854
Daniel Normane5964522019-03-19 10:32:03 -0700855 if not validate_config_lists(
856 system_item_list=system_item_list,
Daniel Norman19b9fe92019-03-19 14:48:02 -0700857 system_misc_info_keys=system_misc_info_keys,
Daniel Normane5964522019-03-19 10:32:03 -0700858 other_item_list=other_item_list):
859 sys.exit(1)
860
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800861 call_func_with_temp_dir(
862 lambda temp_dir: merge_target_files(
863 temp_dir=temp_dir,
864 system_target_files=OPTIONS.system_target_files,
865 system_item_list=system_item_list,
866 system_misc_info_keys=system_misc_info_keys,
867 other_target_files=OPTIONS.other_target_files,
868 other_item_list=other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700869 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700870 output_dir=OPTIONS.output_dir,
871 output_item_list=output_item_list,
Daniel Norman3b64ce12019-04-16 16:11:35 -0700872 output_ota=OPTIONS.output_ota,
Daniel Normanf0318252019-04-15 11:34:56 -0700873 output_super_empty=OPTIONS.output_super_empty,
Daniel Normane5b134a2019-04-17 14:54:06 -0700874 rebuild_recovery=OPTIONS.rebuild_recovery), OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800875
876
877if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -0800878 main()