blob: e9ae5cd96fe5299b60f9dc8818b72d16de9a69be [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.
16
17"""
18This script merges two partial target files packages (one of which contains
19system files, and the other contains non-system files) together, producing a
20complete target files package that can be used to generate an OTA package.
21
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
57 --rebuild_recovery
58 Rebuild the recovery patch used by non-A/B devices and write it to the
59 system image.
Bill Peckham364c1cc2019-03-29 18:27:23 -070060
61 --keep-tmp
62 Keep tempoary files for debugging purposes.
Bill Peckhame9eb5f92019-02-01 15:52:10 -080063"""
64
65from __future__ import print_function
66
Bill Peckhame9eb5f92019-02-01 15:52:10 -080067import fnmatch
68import logging
69import os
Daniel Normanfdb38812019-04-15 09:47:24 -070070import shutil
Bill Peckhame9eb5f92019-02-01 15:52:10 -080071import sys
72import zipfile
73
74import common
75import add_img_to_target_files
76
77logger = logging.getLogger(__name__)
78OPTIONS = common.OPTIONS
79OPTIONS.verbose = True
Bill Peckhamf753e152019-02-19 18:02:46 -080080OPTIONS.system_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080081OPTIONS.system_item_list = None
82OPTIONS.system_misc_info_keys = None
Bill Peckhamf753e152019-02-19 18:02:46 -080083OPTIONS.other_target_files = None
Daniel Norman2c99c5b2019-03-07 13:01:48 -080084OPTIONS.other_item_list = None
Bill Peckhamf753e152019-02-19 18:02:46 -080085OPTIONS.output_target_files = None
Daniel Normanfdb38812019-04-15 09:47:24 -070086OPTIONS.output_dir = None
87OPTIONS.output_item_list = None
Daniel Normana4911da2019-03-15 14:36:21 -070088OPTIONS.rebuild_recovery = False
Bill Peckhamf753e152019-02-19 18:02:46 -080089OPTIONS.keep_tmp = False
Bill Peckhame9eb5f92019-02-01 15:52:10 -080090
Daniel Norman2c99c5b2019-03-07 13:01:48 -080091# default_system_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -080092# system target files package as is, meaning these items will land in the
93# output target files package exactly as they appear in the input partial
94# system target files package.
95
Daniel Norman2c99c5b2019-03-07 13:01:48 -080096default_system_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -080097 'META/apkcerts.txt',
98 'META/filesystem_config.txt',
99 'META/root_filesystem_config.txt',
100 'META/system_manifest.xml',
101 'META/system_matrix.xml',
102 'META/update_engine_config.txt',
103 'PRODUCT/*',
104 'ROOT/*',
105 'SYSTEM/*',
106]
107
108# system_extract_special_item_list is a list of items to extract from the
109# partial system target files package that need some special processing, such
110# as some sort of combination with items from the partial other target files
111# package.
112
113system_extract_special_item_list = [
114 'META/*',
115]
116
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800117# default_system_misc_info_keys is a list of keys to obtain from the system instance of
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800118# META/misc_info.txt. The remaining keys from the other instance.
119
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800120default_system_misc_info_keys = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800121 'avb_system_hashtree_enable',
122 'avb_system_add_hashtree_footer_args',
123 'avb_system_key_path',
124 'avb_system_algorithm',
125 'avb_system_rollback_index_location',
126 'avb_product_hashtree_enable',
127 'avb_product_add_hashtree_footer_args',
128 'avb_product_services_hashtree_enable',
129 'avb_product_services_add_hashtree_footer_args',
130 'system_root_image',
131 'root_dir',
132 'ab_update',
133 'default_system_dev_certificate',
134 'system_size',
135]
136
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800137# default_other_item_list is a list of items to extract from the partial
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800138# other target files package as is, meaning these items will land in the output
139# target files package exactly as they appear in the input partial other target
140# files package.
141
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800142default_other_item_list = [
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800143 'META/boot_filesystem_config.txt',
144 'META/otakeys.txt',
145 'META/releasetools.py',
146 'META/vendor_filesystem_config.txt',
147 'META/vendor_manifest.xml',
148 'META/vendor_matrix.xml',
149 'BOOT/*',
150 'DATA/*',
151 'ODM/*',
152 'OTA/android-info.txt',
153 'PREBUILT_IMAGES/*',
154 'RADIO/*',
155 'VENDOR/*',
156]
157
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800158# other_extract_special_item_list is a list of items to extract from the
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800159# partial other target files package that need some special processing, such as
160# some sort of combination with items from the partial system target files
161# package.
162
163other_extract_special_item_list = [
164 'META/*',
165]
166
167
168def extract_items(target_files, target_files_temp_dir, extract_item_list):
169 """Extract items from target files to temporary directory.
170
171 This function extracts from the specified target files zip archive into the
172 specified temporary directory, the items specified in the extract item list.
173
174 Args:
175 target_files: The target files zip archive from which to extract items.
176
177 target_files_temp_dir: The temporary directory where the extracted items
178 will land.
179
180 extract_item_list: A list of items to extract.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800181 """
182
183 logger.info('extracting from %s', target_files)
184
185 # Filter the extract_item_list to remove any items that do not exist in the
186 # zip file. Otherwise, the extraction step will fail.
187
188 with zipfile.ZipFile(
189 target_files,
190 'r',
191 allowZip64=True) as target_files_zipfile:
192 target_files_namelist = target_files_zipfile.namelist()
193
194 filtered_extract_item_list = []
195 for pattern in extract_item_list:
196 matching_namelist = fnmatch.filter(target_files_namelist, pattern)
197 if not matching_namelist:
198 logger.warning('no match for %s', pattern)
199 else:
200 filtered_extract_item_list.append(pattern)
201
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800202 # Extract from target_files into target_files_temp_dir the
203 # filtered_extract_item_list.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800204
Bill Peckham8ff3fbd2019-02-22 10:57:43 -0800205 common.UnzipToDir(
206 target_files,
207 target_files_temp_dir,
208 filtered_extract_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800209
210
Daniel Normanfdb38812019-04-15 09:47:24 -0700211def copy_items(from_dir, to_dir, patterns):
212 """Similar to extract_items() except uses an input dir instead of zip."""
213 file_paths = []
214 for dirpath, _, filenames in os.walk(from_dir):
215 file_paths.extend(os.path.relpath(path=os.path.join(dirpath, filename),
216 start=from_dir) for filename in filenames)
217
218 filtered_file_paths = set()
219 for pattern in patterns:
220 filtered_file_paths.update(fnmatch.filter(file_paths, pattern))
221
222 for file_path in filtered_file_paths:
223 original_file_path = os.path.join(from_dir, file_path)
224 copied_file_path = os.path.join(to_dir, file_path)
225 copied_file_dir = os.path.dirname(copied_file_path)
226 if not os.path.exists(copied_file_dir):
227 os.makedirs(copied_file_dir)
228 if os.path.islink(original_file_path):
229 os.symlink(os.readlink(original_file_path), copied_file_path)
230 else:
231 shutil.copyfile(original_file_path, copied_file_path)
232
233
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800234def read_config_list(config_file_path):
235 """Reads a config file into a list of strings.
236
237 Expects the file to be newline-separated.
238
239 Args:
240 config_file_path: The path to the config file to open and read.
241 """
242 with open(config_file_path) as config_file:
243 return config_file.read().splitlines()
244
245
Daniel Norman19b9fe92019-03-19 14:48:02 -0700246def validate_config_lists(
247 system_item_list,
248 system_misc_info_keys,
249 other_item_list):
Daniel Normane5964522019-03-19 10:32:03 -0700250 """Performs validations on the merge config lists.
251
252 Args:
253 system_item_list: The list of items to extract from the partial
254 system target files package as is.
255
Daniel Norman19b9fe92019-03-19 14:48:02 -0700256 system_misc_info_keys: A list of keys to obtain from the system instance
257 of META/misc_info.txt. The remaining keys from the other instance.
258
Daniel Normane5964522019-03-19 10:32:03 -0700259 other_item_list: The list of items to extract from the partial
260 other target files package as is.
261
262 Returns:
263 False if a validation fails, otherwise true.
264 """
265 default_combined_item_set = set(default_system_item_list)
266 default_combined_item_set.update(default_other_item_list)
267
268 combined_item_set = set(system_item_list)
269 combined_item_set.update(other_item_list)
270
271 # Check that the merge config lists are not missing any item specified
272 # by the default config lists.
273 difference = default_combined_item_set.difference(combined_item_set)
274 if difference:
275 logger.error('Missing merge config items: %s' % list(difference))
276 logger.error('Please ensure missing items are in either the '
277 'system-item-list or other-item-list files provided to '
278 'this script.')
279 return False
280
Daniel Norman19b9fe92019-03-19 14:48:02 -0700281 if ('dynamic_partition_list' in system_misc_info_keys) or (
282 'super_partition_groups' in system_misc_info_keys):
283 logger.error('Dynamic partition misc info keys should come from '
284 'the other instance of META/misc_info.txt.')
285 return False
286
Daniel Normane5964522019-03-19 10:32:03 -0700287 return True
288
289
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800290def process_ab_partitions_txt(
291 system_target_files_temp_dir,
292 other_target_files_temp_dir,
293 output_target_files_temp_dir):
294 """Perform special processing for META/ab_partitions.txt
295
296 This function merges the contents of the META/ab_partitions.txt files from
297 the system directory and the other directory, placing the merged result in
298 the output directory. The precondition in that the files are already
299 extracted. The post condition is that the output META/ab_partitions.txt
300 contains the merged content. The format for each ab_partitions.txt a one
301 partition name per line. The output file contains the union of the parition
302 names.
303
304 Args:
305 system_target_files_temp_dir: The name of a directory containing the
306 special items extracted from the system target files package.
307
308 other_target_files_temp_dir: The name of a directory containing the
309 special items extracted from the other target files package.
310
311 output_target_files_temp_dir: The name of a directory that will be used
312 to create the output target files package after all the special cases
313 are processed.
314 """
315
316 system_ab_partitions_txt = os.path.join(
317 system_target_files_temp_dir, 'META', 'ab_partitions.txt')
318
319 other_ab_partitions_txt = os.path.join(
320 other_target_files_temp_dir, 'META', 'ab_partitions.txt')
321
322 with open(system_ab_partitions_txt) as f:
323 system_ab_partitions = f.read().splitlines()
324
325 with open(other_ab_partitions_txt) as f:
326 other_ab_partitions = f.read().splitlines()
327
328 output_ab_partitions = set(system_ab_partitions + other_ab_partitions)
329
330 output_ab_partitions_txt = os.path.join(
331 output_target_files_temp_dir, 'META', 'ab_partitions.txt')
332
333 with open(output_ab_partitions_txt, 'w') as output:
334 for partition in sorted(output_ab_partitions):
335 output.write('%s\n' % partition)
336
337
Bill Peckham364c1cc2019-03-29 18:27:23 -0700338def append_recovery_to_filesystem_config(output_target_files_temp_dir):
339 """Perform special processing for META/filesystem_config.txt
340
341 This function appends recovery information to META/filesystem_config.txt
342 so that recovery patch regeneration will succeed.
343
344 Args:
345 output_target_files_temp_dir: The name of a directory that will be used
346 to create the output target files package after all the special cases
347 are processed. We find filesystem_config.txt here.
348 """
349
350 filesystem_config_txt = os.path.join(
351 output_target_files_temp_dir,
352 'META',
353 'filesystem_config.txt')
354
355 with open(filesystem_config_txt, 'a') as f:
356 # TODO(bpeckham) this data is hard coded. It should be generated
357 # programmatically.
358 f.write(
359 'system/bin/install-recovery.sh 0 0 750 '
360 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
361 f.write(
362 'system/recovery-from-boot.p 0 0 644 '
363 'selabel=u:object_r:system_file:s0 capabilities=0x0\n')
364 f.write(
365 'system/etc/recovery.img 0 0 440 '
366 'selabel=u:object_r:install_recovery_exec:s0 capabilities=0x0\n')
367
368
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800369def process_misc_info_txt(
370 system_target_files_temp_dir,
371 other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800372 output_target_files_temp_dir,
373 system_misc_info_keys):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800374 """Perform special processing for META/misc_info.txt
375
376 This function merges the contents of the META/misc_info.txt files from the
377 system directory and the other directory, placing the merged result in the
378 output directory. The precondition in that the files are already extracted.
379 The post condition is that the output META/misc_info.txt contains the merged
380 content.
381
382 Args:
383 system_target_files_temp_dir: The name of a directory containing the
384 special items extracted from the system target files package.
385
386 other_target_files_temp_dir: The name of a directory containing the
387 special items extracted from the other target files package.
388
389 output_target_files_temp_dir: The name of a directory that will be used
390 to create the output target files package after all the special cases
391 are processed.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800392
393 system_misc_info_keys: A list of keys to obtain from the system instance
394 of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800395 """
396
397 def read_helper(d):
398 misc_info_txt = os.path.join(d, 'META', 'misc_info.txt')
399 with open(misc_info_txt) as f:
400 return list(f.read().splitlines())
401
402 system_info_dict = common.LoadDictionaryFromLines(
403 read_helper(system_target_files_temp_dir))
404
405 # We take most of the misc info from the other target files.
406
407 merged_info_dict = common.LoadDictionaryFromLines(
408 read_helper(other_target_files_temp_dir))
409
410 # Replace certain values in merged_info_dict with values from
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800411 # system_info_dict.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800412
413 for key in system_misc_info_keys:
414 merged_info_dict[key] = system_info_dict[key]
415
Daniel Norman19b9fe92019-03-19 14:48:02 -0700416 # Merge misc info keys used for Dynamic Partitions.
417 if (merged_info_dict.get('use_dynamic_partitions') == 'true') and (
418 system_info_dict.get('use_dynamic_partitions') == 'true'):
419 merged_info_dict['dynamic_partition_list'] = '%s %s' % (
420 system_info_dict.get('dynamic_partition_list', ''),
421 merged_info_dict.get('dynamic_partition_list', ''))
422 # Partition groups and group sizes are defined by the other (non-system)
423 # misc info file because these values may vary for each board that uses
424 # a shared system image.
425 for partition_group in merged_info_dict['super_partition_groups'].split(' '):
426 if ('super_%s_group_size' % partition_group) not in merged_info_dict:
427 raise common.ExternalError(
428 'Other META/misc_info.txt does not contain required key '
429 'super_%s_group_size.' % partition_group)
430 key = 'super_%s_partition_list' % partition_group
431 merged_info_dict[key] = '%s %s' % (
432 system_info_dict.get(key, ''),
433 merged_info_dict.get(key, ''))
434
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800435 output_misc_info_txt = os.path.join(
436 output_target_files_temp_dir,
437 'META', 'misc_info.txt')
438
439 sorted_keys = sorted(merged_info_dict.keys())
440
441 with open(output_misc_info_txt, 'w') as output:
442 for key in sorted_keys:
443 output.write('{}={}\n'.format(key, merged_info_dict[key]))
444
445
446def process_file_contexts_bin(temp_dir, output_target_files_temp_dir):
447 """Perform special processing for META/file_contexts.bin.
448
449 This function combines plat_file_contexts and vendor_file_contexts, which are
450 expected to already be extracted in temp_dir, to produce a merged
451 file_contexts.bin that will land in temp_dir at META/file_contexts.bin.
452
453 Args:
454 temp_dir: The name of a scratch directory that this function can use for
455 intermediate files generated during processing.
456
457 output_target_files_temp_dir: The name of the working directory that must
458 already contain plat_file_contexts and vendor_file_contexts (in the
459 appropriate sub directories), and to which META/file_contexts.bin will be
460 written.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800461 """
462
463 # To create a merged file_contexts.bin file, we use the system and vendor
464 # file contexts files as input, the m4 tool to combine them, the sorting tool
465 # to sort, and finally the sefcontext_compile tool to generate the final
466 # output. We currently omit a checkfc step since the files had been checked
467 # as part of the build.
468
469 # The m4 step concatenates the two input files contexts files. Since m4
470 # writes to stdout, we receive that into an array of bytes, and then write it
471 # to a file.
472
473 # Collect the file contexts that we're going to combine from SYSTEM, VENDOR,
474 # PRODUCT, and ODM. We require SYSTEM and VENDOR, but others are optional.
475
476 file_contexts_list = []
477
478 for partition in ['SYSTEM', 'VENDOR', 'PRODUCT', 'ODM']:
479 prefix = 'plat' if partition == 'SYSTEM' else partition.lower()
480
481 file_contexts = os.path.join(
482 output_target_files_temp_dir,
483 partition, 'etc', 'selinux', prefix + '_file_contexts')
484
485 mandatory = partition in ['SYSTEM', 'VENDOR']
486
487 if mandatory or os.path.isfile(file_contexts):
488 file_contexts_list.append(file_contexts)
489 else:
490 logger.warning('file not found: %s', file_contexts)
491
492 command = ['m4', '--fatal-warnings', '-s'] + file_contexts_list
493
494 merged_content = common.RunAndCheckOutput(command, verbose=False)
495
496 merged_file_contexts_txt = os.path.join(temp_dir, 'merged_file_contexts.txt')
497
498 with open(merged_file_contexts_txt, 'wb') as f:
499 f.write(merged_content)
500
501 # The sort step sorts the concatenated file.
502
503 sorted_file_contexts_txt = os.path.join(temp_dir, 'sorted_file_contexts.txt')
504 command = ['fc_sort', merged_file_contexts_txt, sorted_file_contexts_txt]
Bill Peckham889b0c62019-02-21 18:53:37 -0800505 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800506
507 # Finally, the compile step creates the final META/file_contexts.bin.
508
509 file_contexts_bin = os.path.join(
510 output_target_files_temp_dir,
511 'META', 'file_contexts.bin')
512
513 command = [
514 'sefcontext_compile',
515 '-o', file_contexts_bin,
516 sorted_file_contexts_txt,
517 ]
518
Bill Peckham889b0c62019-02-21 18:53:37 -0800519 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800520
521
522def process_special_cases(
523 temp_dir,
524 system_target_files_temp_dir,
525 other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800526 output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700527 system_misc_info_keys,
528 rebuild_recovery
529):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800530 """Perform special-case processing for certain target files items.
531
532 Certain files in the output target files package require special-case
533 processing. This function performs all that special-case processing.
534
535 Args:
536 temp_dir: The name of a scratch directory that this function can use for
537 intermediate files generated during processing.
538
539 system_target_files_temp_dir: The name of a directory containing the
540 special items extracted from the system target files package.
541
542 other_target_files_temp_dir: The name of a directory containing the
543 special items extracted from the other target files package.
544
545 output_target_files_temp_dir: The name of a directory that will be used
546 to create the output target files package after all the special cases
547 are processed.
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800548
549 system_misc_info_keys: A list of keys to obtain from the system instance
550 of META/misc_info.txt. The remaining keys from the other instance.
Bill Peckham364c1cc2019-03-29 18:27:23 -0700551
552 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
553 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800554 """
555
Bill Peckham364c1cc2019-03-29 18:27:23 -0700556 if 'ab_update' in system_misc_info_keys:
557 process_ab_partitions_txt(
558 system_target_files_temp_dir=system_target_files_temp_dir,
559 other_target_files_temp_dir=other_target_files_temp_dir,
560 output_target_files_temp_dir=output_target_files_temp_dir)
561
562 if rebuild_recovery:
563 append_recovery_to_filesystem_config(
564 output_target_files_temp_dir=output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800565
566 process_misc_info_txt(
567 system_target_files_temp_dir=system_target_files_temp_dir,
568 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800569 output_target_files_temp_dir=output_target_files_temp_dir,
570 system_misc_info_keys=system_misc_info_keys)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800571
Bill Peckham889b0c62019-02-21 18:53:37 -0800572 process_file_contexts_bin(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800573 temp_dir=temp_dir,
574 output_target_files_temp_dir=output_target_files_temp_dir)
575
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800576
577def merge_target_files(
578 temp_dir,
579 system_target_files,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800580 system_item_list,
581 system_misc_info_keys,
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800582 other_target_files,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800583 other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700584 output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700585 output_dir,
586 output_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700587 rebuild_recovery):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800588 """Merge two target files packages together.
589
590 This function takes system and other target files packages as input, performs
591 various file extractions, special case processing, and finally creates a
592 merged zip archive as output.
593
594 Args:
595 temp_dir: The name of a directory we use when we extract items from the
596 input target files packages, and also a scratch directory that we use for
597 temporary files.
598
599 system_target_files: The name of the zip archive containing the system
600 partial target files package.
601
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800602 system_item_list: The list of items to extract from the partial system
603 target files package as is, meaning these items will land in the output
604 target files package exactly as they appear in the input partial system
605 target files package.
606
607 system_misc_info_keys: The list of keys to obtain from the system instance
608 of META/misc_info.txt. The remaining keys from the other instance.
609
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800610 other_target_files: The name of the zip archive containing the other
611 partial target files package.
612
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800613 other_item_list: The list of items to extract from the partial other
614 target files package as is, meaning these items will land in the output
615 target files package exactly as they appear in the input partial other
616 target files package.
617
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800618 output_target_files: The name of the output zip archive target files
619 package created by merging system and other.
Daniel Normana4911da2019-03-15 14:36:21 -0700620
621 rebuild_recovery: If true, rebuild the recovery patch used by non-A/B
622 devices and write it to the system image.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800623 """
624
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800625 logger.info(
626 'starting: merge system %s and other %s into output %s',
627 system_target_files,
628 other_target_files,
629 output_target_files)
630
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800631 # Create directory names that we'll use when we extract files from system,
632 # and other, and for zipping the final output.
633
634 system_target_files_temp_dir = os.path.join(temp_dir, 'system')
635 other_target_files_temp_dir = os.path.join(temp_dir, 'other')
636 output_target_files_temp_dir = os.path.join(temp_dir, 'output')
637
638 # Extract "as is" items from the input system partial target files package.
639 # We extract them directly into the output temporary directory since the
640 # items do not need special case processing.
641
Bill Peckham889b0c62019-02-21 18:53:37 -0800642 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800643 target_files=system_target_files,
644 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800645 extract_item_list=system_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800646
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800647 # Extract "as is" items from the input other partial target files package. We
648 # extract them directly into the output temporary directory since the items
649 # do not need special case processing.
650
Bill Peckham889b0c62019-02-21 18:53:37 -0800651 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800652 target_files=other_target_files,
653 target_files_temp_dir=output_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800654 extract_item_list=other_item_list)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800655
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800656 # Extract "special" items from the input system partial target files package.
657 # We extract these items to different directory since they require special
658 # processing before they will end up in the output directory.
659
Bill Peckham889b0c62019-02-21 18:53:37 -0800660 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800661 target_files=system_target_files,
662 target_files_temp_dir=system_target_files_temp_dir,
663 extract_item_list=system_extract_special_item_list)
664
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800665 # Extract "special" items from the input other partial target files package.
666 # We extract these items to different directory since they require special
667 # processing before they will end up in the output directory.
668
Bill Peckham889b0c62019-02-21 18:53:37 -0800669 extract_items(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800670 target_files=other_target_files,
671 target_files_temp_dir=other_target_files_temp_dir,
672 extract_item_list=other_extract_special_item_list)
673
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800674 # Now that the temporary directories contain all the extracted files, perform
675 # special case processing on any items that need it. After this function
676 # completes successfully, all the files we need to create the output target
677 # files package are in place.
678
Bill Peckham889b0c62019-02-21 18:53:37 -0800679 process_special_cases(
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800680 temp_dir=temp_dir,
681 system_target_files_temp_dir=system_target_files_temp_dir,
682 other_target_files_temp_dir=other_target_files_temp_dir,
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800683 output_target_files_temp_dir=output_target_files_temp_dir,
Bill Peckham364c1cc2019-03-29 18:27:23 -0700684 system_misc_info_keys=system_misc_info_keys,
685 rebuild_recovery=rebuild_recovery)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800686
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800687 # Regenerate IMAGES in the temporary directory.
688
Daniel Normana4911da2019-03-15 14:36:21 -0700689 add_img_args = ['--verbose']
690 if rebuild_recovery:
691 add_img_args.append('--rebuild_recovery')
692 add_img_args.append(output_target_files_temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800693
694 add_img_to_target_files.main(add_img_args)
695
Daniel Normanfdb38812019-04-15 09:47:24 -0700696 # Finally, create the output target files zip archive and/or copy the
697 # output items to the output target files directory.
698
699 if output_dir:
700 copy_items(output_target_files_temp_dir, output_dir, output_item_list)
701
702 if not output_target_files:
703 return
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800704
705 output_zip = os.path.abspath(output_target_files)
706 output_target_files_list = os.path.join(temp_dir, 'output.list')
707 output_target_files_meta_dir = os.path.join(
708 output_target_files_temp_dir, 'META')
709
710 command = [
711 'find',
712 output_target_files_meta_dir,
713 ]
714 # TODO(bpeckham): sort this to be more like build.
715 meta_content = common.RunAndCheckOutput(command, verbose=False)
716 command = [
717 'find',
718 output_target_files_temp_dir,
719 '-path',
720 output_target_files_meta_dir,
721 '-prune',
722 '-o',
723 '-print'
724 ]
725 # TODO(bpeckham): sort this to be more like build.
726 other_content = common.RunAndCheckOutput(command, verbose=False)
727
728 with open(output_target_files_list, 'wb') as f:
729 f.write(meta_content)
730 f.write(other_content)
731
732 command = [
Bill Peckhamf753e152019-02-19 18:02:46 -0800733 'soong_zip',
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800734 '-d',
735 '-o', output_zip,
736 '-C', output_target_files_temp_dir,
737 '-l', output_target_files_list,
738 ]
739 logger.info('creating %s', output_target_files)
Bill Peckham889b0c62019-02-21 18:53:37 -0800740 common.RunAndWait(command, verbose=True)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800741
742
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800743def call_func_with_temp_dir(func, keep_tmp):
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800744 """Manage the creation and cleanup of the temporary directory.
745
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800746 This function calls the given function after first creating a temporary
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800747 directory. It also cleans up the temporary directory.
748
749 Args:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800750 func: The function to call. Should accept one parameter, the path to
751 the temporary directory.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800752
753 keep_tmp: Keep the temporary directory after processing is complete.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800754 """
755
756 # Create a temporary directory. This will serve as the parent of directories
757 # we use when we extract items from the input target files packages, and also
758 # a scratch directory that we use for temporary files.
759
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800760 temp_dir = common.MakeTempDir(prefix='merge_target_files_')
761
762 try:
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800763 func(temp_dir)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800764 except:
765 raise
766 finally:
767 if keep_tmp:
768 logger.info('keeping %s', temp_dir)
769 else:
770 common.Cleanup()
771
772
773def main():
774 """The main function.
775
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800776 Process command line arguments, then call merge_target_files to
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800777 perform the heavy lifting.
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800778 """
779
780 common.InitLogging()
781
Bill Peckhamf753e152019-02-19 18:02:46 -0800782 def option_handler(o, a):
783 if o == '--system-target-files':
784 OPTIONS.system_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800785 elif o == '--system-item-list':
786 OPTIONS.system_item_list = a
787 elif o == '--system-misc-info-keys':
788 OPTIONS.system_misc_info_keys = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800789 elif o == '--other-target-files':
790 OPTIONS.other_target_files = a
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800791 elif o == '--other-item-list':
792 OPTIONS.other_item_list = a
Bill Peckhamf753e152019-02-19 18:02:46 -0800793 elif o == '--output-target-files':
794 OPTIONS.output_target_files = a
Daniel Normanfdb38812019-04-15 09:47:24 -0700795 elif o == '--output-dir':
796 OPTIONS.output_dir = a
797 elif o == '--output-item-list':
798 OPTIONS.output_item_list = a
Daniel Normana4911da2019-03-15 14:36:21 -0700799 elif o == '--rebuild_recovery':
800 OPTIONS.rebuild_recovery = True
Bill Peckham364c1cc2019-03-29 18:27:23 -0700801 elif o == '--keep-tmp':
Bill Peckhamf753e152019-02-19 18:02:46 -0800802 OPTIONS.keep_tmp = True
803 else:
804 return False
805 return True
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800806
Bill Peckhamf753e152019-02-19 18:02:46 -0800807 args = common.ParseOptions(
808 sys.argv[1:], __doc__,
809 extra_long_opts=[
810 'system-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800811 'system-item-list=',
812 'system-misc-info-keys=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800813 'other-target-files=',
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800814 'other-item-list=',
Bill Peckhamf753e152019-02-19 18:02:46 -0800815 'output-target-files=',
Daniel Normanfdb38812019-04-15 09:47:24 -0700816 'output-dir=',
817 'output-item-list=',
Daniel Normana4911da2019-03-15 14:36:21 -0700818 'rebuild_recovery',
Bill Peckham364c1cc2019-03-29 18:27:23 -0700819 'keep-tmp',
Bill Peckhamf753e152019-02-19 18:02:46 -0800820 ],
821 extra_option_handler=option_handler)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800822
Bill Peckham889b0c62019-02-21 18:53:37 -0800823 if (len(args) != 0 or
Bill Peckhamf753e152019-02-19 18:02:46 -0800824 OPTIONS.system_target_files is None or
Daniel Normanfdb38812019-04-15 09:47:24 -0700825 OPTIONS.other_target_files is None or (
826 OPTIONS.output_target_files is None and
827 OPTIONS.output_dir is None) or (
828 OPTIONS.output_dir is not None and
829 OPTIONS.output_item_list is None)):
Bill Peckhamf753e152019-02-19 18:02:46 -0800830 common.Usage(__doc__)
Bill Peckham889b0c62019-02-21 18:53:37 -0800831 sys.exit(1)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800832
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800833 if OPTIONS.system_item_list:
834 system_item_list = read_config_list(OPTIONS.system_item_list)
835 else:
836 system_item_list = default_system_item_list
837
838 if OPTIONS.system_misc_info_keys:
839 system_misc_info_keys = read_config_list(OPTIONS.system_misc_info_keys)
840 else:
841 system_misc_info_keys = default_system_misc_info_keys
842
843 if OPTIONS.other_item_list:
844 other_item_list = read_config_list(OPTIONS.other_item_list)
845 else:
846 other_item_list = default_other_item_list
847
Daniel Normanfdb38812019-04-15 09:47:24 -0700848 if OPTIONS.output_item_list:
849 output_item_list = read_config_list(OPTIONS.output_item_list)
850 else:
851 output_item_list = None
852
Daniel Normane5964522019-03-19 10:32:03 -0700853 if not validate_config_lists(
854 system_item_list=system_item_list,
Daniel Norman19b9fe92019-03-19 14:48:02 -0700855 system_misc_info_keys=system_misc_info_keys,
Daniel Normane5964522019-03-19 10:32:03 -0700856 other_item_list=other_item_list):
857 sys.exit(1)
858
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800859 call_func_with_temp_dir(
860 lambda temp_dir: merge_target_files(
861 temp_dir=temp_dir,
862 system_target_files=OPTIONS.system_target_files,
863 system_item_list=system_item_list,
864 system_misc_info_keys=system_misc_info_keys,
865 other_target_files=OPTIONS.other_target_files,
866 other_item_list=other_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700867 output_target_files=OPTIONS.output_target_files,
Daniel Normanfdb38812019-04-15 09:47:24 -0700868 output_dir=OPTIONS.output_dir,
869 output_item_list=output_item_list,
Daniel Normana4911da2019-03-15 14:36:21 -0700870 rebuild_recovery=OPTIONS.rebuild_recovery),
Daniel Norman2c99c5b2019-03-07 13:01:48 -0800871 OPTIONS.keep_tmp)
Bill Peckhame9eb5f92019-02-01 15:52:10 -0800872
873
874if __name__ == '__main__':
Bill Peckham889b0c62019-02-21 18:53:37 -0800875 main()